DefinePlugin does not inject variable

I have been trying to figure this out for over an hour now. Here is the subject code:

const ENVIRONMENT = process.env.NODE_ENV;
const BASENAME = process.env.APP_BASENAME;

console.log('process.env', {
    ENVIRONMENT: ENVIRONMENT,
    'process.env': process.env,
    NODE_ENV: process.env.NODE_ENV,
    APP_BASENAME: process.env.APP_BASENAME
});

if (ENVIRONMENT !== 'development' && ENVIRONMENT !== 'production') {
    throw new Error('Unknown ENVIRONMENT.');
}

export {
    BASENAME,
    ENVIRONMENT
};

Here is my webpack config:

const webpack = require('webpack');
const path = require('path');

module.exports = {
    devtool: 'source-map',
    debug: false,
    context: __dirname,
    entry: {
        'app': [
            path.resolve(__dirname, './src/app')
        ]
    },
    output: {
        path: path.resolve(__dirname, './dist'),
        filename: '[name].js',
        publicPath: '/static/'
    },
    plugins: [
        new webpack.optimize.UglifyJsPlugin({
            compressor: {
                /* eslint-disable camelcase */
                screw_ie8: true,
                /* eslint-enable */
                warnings: false
            }
        }),
        new webpack.DefinePlugin({
            'process.env.NODE_ENV': '"production"',
            'process.env.APP_BASENAME': '"' + (process.env.APP_BASENAME || '') + '"'
        }),
        new webpack.DefinePlugin({
            'process.env': {
                NODE_ENV: '"production"',
                APP_BASENAME: '"' + (process.env.APP_BASENAME || '') + '"'
            }
        }),
        new webpack.optimize.OccurrenceOrderPlugin(),
        new webpack.optimize.DedupePlugin(),
        new webpack.NoErrorsPlugin()
    ],
    module: {
        loaders: [
            {
                include: path.resolve(__dirname, './src'),
                loader: 'babel',
                test: /\.js$/,
            },
            {
                loaders: [
                    'style?sourceMap',
                    'css?modules&importLoaders=1&localIdentName=[name]___[local]___[hash:base64:5]',
                    'resolve-url',
                    'sass?sourceMap'
                ],
                test: /\.scss$/
            }
        ]
    }
};

As you can see, I have tried multiple methods of using DefinePlugin:

new webpack.DefinePlugin({
    'process.env.NODE_ENV': '"production"',
    'process.env.APP_BASENAME': '"' + (process.env.APP_BASENAME || '') + '"'
}),
new webpack.DefinePlugin({
    'process.env': {
        NODE_ENV: '"production"',
        APP_BASENAME: '"' + (process.env.APP_BASENAME || '') + '"'
    }
}),

Here is the console output:

{
    APP_BASENAME: "/campaign-master/upload-static",
    ENVIRONMENT: undefined,
    NODE_ENV: undefined,
    process.env: {
        APP_BASENAME: "/campaign-master/upload-static",
        NODE_ENV: "production"
    }
}

The script execution ends with an exception:

Uncaught Error: Unknown ENVIRONMENT.

As a result of the condition that you can see in the config.js.

What is the reason process.env.NODE_ENV is not getting replaced?

Author: Fantashit

9 thoughts on “DefinePlugin does not inject variable

  1. That was painful experience.

    My .babelrc has been configured as:

    {
        "presets": [
            "es2015",
            "stage-0",
            "react"
        ],
        "plugins": [
            "transform-export-default-name",
            "lodash-modularize",
            "transform-node-env-inline"
        ],
        "env": {
            "development": {
                "presets": [
                    "react-hmre"
                ],
                "plugins": [
                    "typecheck"
                ]
            }
        }
    }
    

    while I was executing webpack using:

    APP_BASENAME='/campaign-master/upload-static' webpack --config ./webpack.config.production.js

    i.e. babel-preset-react-hmre is breaking DefinePlugin.

  2. I should confess that the problem I reported was actually of my own making. Sadly, I can’t actually recall the details of my error, but I can confirm that DefinePlugin is working ok for me now (using Webpack 3.5.5). eg. the following works as expected:

    new webpack.DefinePlugin({
    ‘process.env.NODE_ENV’: JSON.stringify(process.env.NODE_ENV),
    ‘process.env.BUILD_TARGET’: JSON.stringify(build),
    }),

    hth.

  3. I am having the same problem with webpack-3.5.5. typescript 2.5.2

    "dependencies": {                       
      "@types/react": "^16.0.5",            
      "@types/react-dom": "^15.5.4",        
      "material-ui": "^0.19.1",             
      "react": "^15.6.1",                   
      "react-dom": "^15.6.1",               
      "webpack": "^3.5.6"                   
    },                                      
    "devDependencies": {                    
      "@types/aws-sdk": "^2.7.0",           
      "@types/material-ui": "^0.18.0",      
      "@types/node": "^8.0.26",             
      "awesome-typescript-loader": "^3.2.3",
      "react-hot-loader": "^3.0.0-beta.7",  
      "source-map-loader": "^0.2.1",        
      "typescript": "^2.5.2",               
      "webpack-dev-server": "^2.7.1"        
    }                                       
  4. Hmm, I was just having this issue and it was trolling me. process.env was showing as an empty object, but after I read this #868 I tried explicitly calling process.env.NODE_ENV and process.env.APP_VERSION, and boom it worked fine. Watchout for that. It could be some of yours’ problems…

        new webpack.DefinePlugin({
            'process.env.NODE_ENV': JSON.stringify('development'),
            'process.env.APP_VERSION': JSON.stringify(process.env.npm_package_version),
        })
    

    Inside some module:

    console.log(process.env.APP_VERSION) === 0.0.1

    console.log(process.env) === {}

  5. @amackintosh This is because DefinePlugin doesn’t build any object – it just replaces all occurrences of process.env.NODE_ENV in code with the constant you provided. In short, this works like find-and-replace variable with value 🙂

  6. @donce Thanks a lot. It works!! I have been researching the reason why everything was undefined when I tried getting the value from the window object. This DefinePlugin thing is really a trick.

  7.     plugins: [
          new webpack.DefinePlugin({
            'process.env.NODE_ENV': JSON.stringify('development'), // nested in object, requires quotes
            CUSTOM_VAR: JSON.stringify('value goes here'), // no quotes needed, string value
            ENABLE_DEBUG: JSON.stringify(true), // boolean value
          }),
        ],
  8. I’m not sure why it’s called “DefinePlugin” — it’s more like a “identifier substitution plugin”.

    Also you might want to set node: false in the webpack config. By default webpack will mock node globals for the browser, which is why process and process.env are defined instead of being completely undefined. That threw me off for a second.

  9. As many people have pointed out, the substitution is a compile-time operation (static), i.e. it is carried out when the bundle is built, as opposed to being evaluated when the resulting application is run (dynamic) in node or the browser. You may pass in a computed value inside webpack.config.js but the value that ends up inside the bundle will be a fixed value determined before the application is ever run. An easy way to distinguish these is to ask yourself:
    Do I need to know the actual value of the variable before the bundle is built?
    if yes, then DefinePlugin can help you with that. If not, then you need another solution where the process that serves your bundle to the client will pass in the required values)

    In other words:
    the purpose is to modify the bundle being built (e.g. a development bundle that facilitates debugging vs. highly optimized production bundle).
    It is NOT a means to modify the behaviour of an already built bundle when it is run!

    Another significant thing I noticed is that it doesn’t work well in combination with webpack’s –watch mode. That also makes sense as webpack will aggressively cache already compiled modules and only recompile them if the watched corresponding source files are changed. If we change the environment variables we pass in, the source files still remain unchanged thus webpack will happily skip recompiling those modules if it’s operating in watch mode. We can work around this by deleting the cache before running webpack:

    rm -rf node_modules/.cache && webpack --watch ...

Comments are closed.