doobean
doobean

Reputation: 2148

How to set environment variables on React with custom webpack

My React app isn't run by create-react-app, but a custom Webpack config.

I"ve installed dotenv / dotenv-expand / and also dotenv-webpack.

I have .env / .env.development files with API_URL variable in it.

On my url file,

const { API_URL } = process.env

and use this API_URL to fetch data.

But on this file, when I console.log(process.env), it is empty.

I also have tried to update webpack.config.js file with

const Dotenv = require('dotenv-webpack');

and

new Dotenv()

in plugins array.

But still doesn't work.

I also tried having variable name REACT_APP_API_URL but was same result.

Could anyone help me to set the env vars?

Thank you.

webpack.config.js

const webpack = require('webpack')
const Dotenv = require('dotenv-webpack');
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpackMerge = require('webpack-merge')

const modeConfig = env => require(`./build-utils/webpack.${env}`)(env)
const presetConfig = require('./build-utils/loadPresets')

module.exports = ({ mode, presets } = { mode: 'production', presets: [] }) => {
  console.log('mode', mode, 'presets', presets)
  return webpackMerge(
    {
      mode,
      module: {
        rules: [
          {
            test: /\.(png|jpe?g|svg)$/,
            use: {
              loader: 'file-loader',
              options: {
                name: 'assets/[name].[ext]',
              }
            },
          },
        ],
      },
      node: {
        fs: 'empty'
      },
      resolve: {
        extensions: ['.js', '.json'],
      },
      output: {
        filename: 'bundle.js',
        chunkFilename: '[name].lazy-chunk.js',
        path: path.resolve(__dirname, 'build'),
        publicPath: mode === 'development' ? '/' : './'
      },
      devServer: {
        historyApiFallback: true
      },
      plugins: [
        new HtmlWebpackPlugin({
          template: './build-utils/template.html'
        }),
        new webpack.ProgressPlugin(),
        new Dotenv()
      ]
    },
    modeConfig(mode),
    presetConfig({ mode, presets })
  )
}

Upvotes: 2

Views: 8784

Answers (1)

Sherman Hui
Sherman Hui

Reputation: 998

If you're trying to access the env values in your JS files, you typically need to have the dotenv plugin.

const webpack = require('webpack')
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpackMerge = require('webpack-merge')

require('dotenv').config() // may need to set path to your .env file if it isn't at the root at the project

const modeConfig = env => require(`./build-utils/webpack.${env}`)(env)
const presetConfig = require('./build-utils/loadPresets')

module.exports = ({ mode, presets } = { mode: 'production', presets: [] }) => {
  return webpackMerge(
      ...
      plugins: [
        new HtmlWebpackPlugin({
          template: './build-utils/template.html'
        }),
        new webpack.ProgressPlugin(),
        new webpack.DefinePlugin({
           'process.env': {
               NODE_ENV: JSON.stringify(process.env.NODE_ENV),
               SOME_VALUE: JSON.stringify(process.env.SOME_VALUE),
               ...
            }
        })
      ]
    },
    ...
  )
}

NOTE: With this implementation you won't be able to do const { API_URL } = process.env because DefinePlugin does a search and replace of the JavaScript where it will look up any references to process.env.API_URL and replace it with whatever that value is. Therefore API_URL won't exist on porcess.env, so to use it just do process.env.API_URL

You could also use dotenv-webpack, I think you were close to getting it to work.

const webpack = require('webpack')
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpackMerge = require('webpack-merge')

const Dotenv = require('dotenv-webpack');

const modeConfig = env => require(`./build-utils/webpack.${env}`)(env)
const presetConfig = require('./build-utils/loadPresets')

module.exports = ({ mode, presets } = { mode: 'production', presets: [] }) => {
  return webpackMerge(
      ...
      plugins: [
        new HtmlWebpackPlugin({
          template: './build-utils/template.html'
        }),
        new webpack.ProgressPlugin(),
        new Dotenv({
           path: envPath
        })
      ]
    },
    ...
  )
}

If you need more help please share more details in by creating a Minimal, Reproducible Example.

Upvotes: 5

Related Questions