1

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

Nick
  • 624
  • 8
  • 24
  • Pretty sure you have to add it to your webpack config, see accepted answer (and other ones) here: https://stackoverflow.com/questions/46224986/how-to-pass-env-file-variables-to-webpack-config make sure to restart your server too after adding it – Jayce444 Oct 23 '20 at 00:40

4 Answers4

6

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()]
}
Alex Mckay
  • 3,463
  • 16
  • 27
  • I've tried that before. and i get the following `.definitions is not a valid Plugin property - Maybe you meant to use "plugin": [ ["@babel/plugin-transform-runtime", { "definitions": { "process.env.REACT_APP_WEATHERAPI": "\xxxxxx\"" } }]` This is actually the first thing i tried when from reading the docs – Nick Oct 23 '20 at 00:57
  • Check the updated answer. Once you get this sorted I would highly recommend checking out `webpack-merge`. Your current method of splitting dev/prod config is pretty confusing. – Alex Mckay Oct 23 '20 at 02:45
  • hmm thank you. It seemed to get rid of the error i was receiving before, however my app now won't display anything on the webpage. – Nick Oct 23 '20 at 02:55
  • 1
    I have a break shortly, I'll create a repo for you if you'd find that useful? – Alex Mckay Oct 23 '20 at 03:15
  • OMG I was searching for HOURS before I found this. Hundreds of pages suggesting `dotenv`, which doesn't work with webpack, and how many react apps aren't going to use webpack?? Thank you! – Sinister Beard Jul 30 '21 at 12:58
  • Typescript doesn't seem to like this much – shallow.alchemy Mar 06 '22 at 03:22
1

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.

0

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'
}
Wonkledge
  • 1,732
  • 7
  • 16
  • Sorry I should have mentioned that this was the first thing i tried. I get an error of `Module not found: Error: Can't resolve 'fs': in C:\users\....`. After receiving this message i installed `fs` and still received the error – Nick Oct 23 '20 at 00:22
  • well, this is not linked to dotenv and env variable. This error means you cannot access to your basic node package. fs is ship with node js. – Wonkledge Oct 23 '20 at 00:25
  • this isn't a node application. This app is just using react and other front end technologies. – Nick Oct 23 '20 at 00:27
  • under the hood react is using nodejs :p, i edit my answer, give it a try :p – Wonkledge Oct 23 '20 at 00:29
  • 1
    this did get rid of the `fs` error message however I am still getting the `undefined` message in the console when i use `console.log(process.env.REACT_APP_API_KEY)` – Nick Oct 23 '20 at 00:39
  • You can't use `fs` on the client side, `fs` is for accessing the file system. You can't do that through the browser, for obvious security reasons – Jayce444 Oct 23 '20 at 00:40
0

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());

...
Sajib Khan
  • 22,878
  • 9
  • 63
  • 73