Nick
Nick

Reputation: 674

using dotenv with react & webpack

I'm finding information that you can use dotenv with react using

import React from "react"
console.log(process.env.REACT_APP_API_KEY)

however when I create my .env file in the root of my direction i get a undefined message in the console.

I should note that i am NOT using react-create-app.

Here is my .env file

REACT_APP_API_KEY=secretKey

Here is my webpack config file.

Is there any way I can use dotenv without using node.js and creating a small server.

const currentTask = process.env.npm_lifecycle_event;
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const { postcss } = require("postcss-mixins");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const fse = require("fs-extra");

const postCSSPlugins = [
  require("postcss-import"),
  require("postcss-mixins"),
  require("postcss-simple-vars"),
  require("postcss-nested"),
  require("postcss-hexrgba"),
  require("autoprefixer")
];

class RunAfterCompile {
  apply(compiler) {
    compiler.hooks.done.tap("Copy images", function () {
      fse.copySync("./app/assets/images", "./docs/assets/images");
    });
  }
}

let cssConfig = {
  test: /\.css$/i,
  use: [
    "css-loader?url=false",
    { loader: "postcss-loader", options: { plugins: postCSSPlugins } }
  ]
};

let pages = fse
  .readdirSync("./app")
  .filter(function (file) {
    return file.endsWith(".html");
  })
  .map(function (page) {
    return new HtmlWebpackPlugin({
      filename: page,
      template: `./app/${page}`
    });
  });

let config = {
  entry: "./app/assets/scripts/App.js",
  plugins: pages,
  module: {
    rules: [
      cssConfig,
      {
        test: /\.js$/,
        exclude: /(node_modules)/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-react", "@babel/preset-env"],
            plugins: ["@babel/plugin-transform-runtime"]
          }
        }
      }
    ]
  }
};

if (currentTask == "dev") {
  cssConfig.use.unshift("style-loader");
  config.output = {
    filename: "bundled.js",
    path: path.resolve(__dirname, "app")
  };
  config.devServer = {
    before: function (app, server) {
      server._watch("./app/**/*.html");
    },
    contentBase: path.join(__dirname, "app"),
    hot: true,
    port: 3000,
    host: "0.0.0.0",
    historyApiFallback: { index: "/" }
  };
  config.mode = "development";
}

if (currentTask == "build") {
  cssConfig.use.unshift(MiniCssExtractPlugin.loader);
  postCSSPlugins.push(require("cssnano"));
  config.output = {
    filename: "[name].[chunkhash].js",
    chunkFilename: "[name].[chunkhash].js",
    path: path.resolve(__dirname, "docs")
  };
  config.mode = "production";
  config.optimization = {
    splitChunks: { chunks: "all" }
  };
  config.plugins.push(
    new CleanWebpackPlugin(),
    new MiniCssExtractPlugin({ filename: "styles.[chunkhash].css" }),
    new RunAfterCompile()
  );
}

module.exports = config;

i've been at this for a couple of hours now and I can't seem to find what i need online. Hoping someone has ran into this issue before.

thanks

Upvotes: 4

Views: 10407

Answers (4)

user16435030
user16435030

Reputation:

dotenv variables will only be available in webpack and process for things that are not being compiled by webpack.

In order to make your environment variables available in webpack compiled files you need to inject it using webpack's define or enviornment plugins.

https://webpack.js.org/plugins/environment-plugin/

This will replace all environment strings in your files with environment variables during compilation process.

The reason why your key is giving undefined is because when webpack (babel) is compiling it that string doesn't exist because it was never replaced/injected through webpack environment variables.

Upvotes: 1

Sajib Khan
Sajib Khan

Reputation: 24194

I would recommend to use dotenv-webpack to access .env file variable(s).

Add the following in Webpack config file:

// webpack.config.js
const Dotenv = require('dotenv-webpack');


...
let config = {
  entry: "./app/assets/scripts/App.js",
  plugins: pages,
  ...
};

config.plugins.pushes(new Dotenv());

...

Upvotes: 0

Alex Mckay
Alex Mckay

Reputation: 3706

There is a dotenv-webpack plugin specifically for this situation.

Setup is dead simple:

// webpack.config.js
const dotEnv = require('dotenv-webpack')
module.exports = {
  plugins: [new dotEnv()]
}

Docs

EDIT

This answer is too verbose for comments:

You are adding dotEnv to the wrong plugins property.

 module: {
    rules: [
      cssConfig,
      {
        test: /\.js$/,
        exclude: /(node_modules)/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-react", "@babel/preset-env"],
            plugins: [/* WRONG */ new dotEnv(), "@babel/plugin-transform-runtime"]
          }
        }
      }
    ]
  }

When it should be added here:

if (currentTask == "dev") {
  config.plugins = [/* RIGHT */ new dotEnv()]
}

Upvotes: 7

Alexandre LEROY
Alexandre LEROY

Reputation: 2310

at the top of your file where you want use env variables add:

import dotenv from 'dotenv';

dotenv.config();

everything should work just fine :p

Concerning your error with fs module do you try to add following snippet to your webpack config ?

node: {
  fs: 'empty'
}

Upvotes: 0

Related Questions