Webpack 2: -p option does not set NODE_ENV to “production” in webpack config

Is that an upcoming feature or why isn’t the variable set when I try to access it in the webpack config with process.env.NODE_ENV ? I use webpack ^2.1

Furthermore I recognized that when using -p option the UglifyJsPlugin is applied? Don’t see that in the documentation anywhere.

Author: Fantashit

23 thoughts on “Webpack 2: -p option does not set NODE_ENV to “production” in webpack config

  1. NODE_ENV is set in the compiled code, not in the webpack.config.js file. You should not use enviroment variables in your configuration. Pass options via --env.option abc and export a function from the webpack.config.js.

  2. Why should you not use env-variables in the config?

    I have a webpack config, which changes according to NODE_ENV. It’s awesome because it’s in one file and

    • for developing I just run webpack-dev-server
    • for production I run NODE_ENV='production' webpack -p
    const webpack = require('webpack'),
        path = require('path'),
        fs = require('fs')
    
    const SRC = path.resolve(__dirname, "src"),
        NODE_MODULES = path.resolve(__dirname, "node_modules")
    
    /* babel */
    const babelSettings = JSON.parse(fs.readFileSync(".babelrc"))
    
    const config = {
        entry: [
            './src/index.js'
        ],
        module: {
            loaders: [
                {
                    test: /\.jsx?$/,
                    include: SRC,
                    loader: "babel-loader",
                    query: babelSettings
                },
                {
                    test: [
                        /\.png$/,
                        /\.jpg$/
                    ],
                    loader: "url-loader"
                },
                {
                    test: /\.css$/,
                    include: [
                        NODE_MODULES,
                        SRC
                    ],
                    loader: 'style-loader!css-loader!postcss-loader',
                }
            ]
        },
        resolve: {
            root: SRC,
            extensions: [
                '',
                '.js',
                '.jsx'
            ]
        },
        output: {
            path: path.resolve(__dirname, 'public', 'assets'),
            publicPath: '/assets',
            filename: 'bundle.js'
        },
        postcss: [
            require('autoprefixer')
        ],
        plugins: [
            new webpack.DefinePlugin({
                'process.env': {
                    'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
                }
            }),
        ]
    };
    
    if (process.env.NODE_ENV === 'production') {
        config.plugins.push(
            new webpack.optimize.UglifyJsPlugin({
                compress: {
                    screw_ie8: true
                }
            })
        )
        babelSettings.plugins.push("transform-react-inline-elements");
        babelSettings.plugins.push("transform-react-constant-elements");
    
    } else {
        config.devtool = "#cheap-module-source-map"
        config.devServer = {
            contentBase: './public',
            hot: true,
            inline: true,
            host: "0.0.0.0",
            port: 2708
        }
        config.plugins.push(
            new webpack.HotModuleReplacementPlugin()
        );
    }
    
    module.exports = config

    I noticed too that for some reason the output of “webpack -p” is different than just running webpack with the Uglify plugin applied.

  3. Personally, I am not quite getting what you mean by -env.option abcd but I tried this and it doesn’t seem to help with anything. I do believe that doing this automatically based on the -p flag would be reasonable. For the loads of other people that have also run into this behavior wondering “wtf!?” below is dead simple example of what I am currently using to deal with the issue:

    _package.json_

    {
      "name": "webpack_test",
      "version": "1.0.0",
      "description": "",
      "main": "build/bundle.js",
      "scripts": {
        "build": "webpack",
        "build:prod": "webpack -p",
      },
      "author": "Benjamin Baldivia",
      "license": "ISC",
      "devDependencies": {
        "webpack": "^1.13.2"
      }
    }

    _webpack.config.js_

    const webpack = require('webpack');
    const prod = process.argv.indexOf('-p') !== -1;
    
    const config = {
      entry: './src/main.js',
      output: {
        path: 'build',
        filename: 'bundle.js'
      }
    };
    
    
    /*
    This code was seperated from the config for multiple reasons.
    Other conditional things can be added very simply.
    Also, the check for config.plugins is so it is not dependent on the structure above.
    */
    
    config.plugins = config.plugins||[];
    if (prod) {
      config.plugins.push(new webpack.DefinePlugin({
          'process.env': {
              'NODE_ENV': `"production"`
          }
      }));
    } else {
      config.plugins.push(new webpack.DefinePlugin({
          'process.env': {
              'NODE_ENV': `""`
          }
      }));
    }
    
    module.exports = config;

    _src/main.js_

    if (process.env.NODE_ENV === 'production') {
      module.exports = require('./prod.js')
    } else {
      module.exports = require('./dev.js')
    }

    _src/dev.js_

    console.log("I am in dev");

    src/prod.js

    console.log("I am in production");

    The key here is really only the webpack.config.js I only included the rest for it to be a complete example of it’s usage. Below we can see the results:

    npm run build
    
    # OUTPUT
    
    #> webpack_test@1.0.0 build C:\Users\Goblin\dev\webpack_test
    #> webpack
    #
    #Hash: 133cddf132a8bd0ff743
    #Version: webpack 1.13.2
    #Time: 42ms
    #    Asset     Size  Chunks             Chunk Names
    #bundle.js  1.61 kB       0  [emitted]  main
    #   [0] ./src/main.js 140 bytes {0} [built]
    #   [1] ./src/dev.js 29 bytes {0} [built]
    npm run build:prod
    
    #OUTPUT
    
    #> webpack_test@1.0.0 build:prod C:\Users\Goblin\dev\webpack_test
    #> webpack -p
    #Hash: e5112caeb4609ddc76a9
    #Version: webpack 1.13.2
    #Time: 79ms
    #    Asset       Size  Chunks             Chunk Names
    #bundle.js  283 bytes       0  [emitted]  main
    #   [0] ./src/main.js 140 bytes {0} [built]
    #   [1] ./src/prod.js 38 bytes {0} [built]
    #
    #WARNING in bundle.js from UglifyJs
    #Condition always true [./src/main.js:1,0]
    #Dropping unreachable code [./src/main.js:4,0]

    This is much mode in-line with what I believe users expect when using the -p flag. It would be REALLY nice if this was the default behavior when using the flag. I would be more than willing to submit a PR if this is deemed acceptable default behavior. I know I ran into this issue and ran around in circles working around it and while I was I know I looked up quite a few “solutions” (some blogged about) meaning there are quite a few people with this specific problem.

  4. Agree, it’s really confusing that is says this in the changelog:

    -p sets NODE_ENV = “production”

    and then process.env.NODE_ENV is undefined in the webpack config.

    I usually call webpack setting NODE_ENV from the command line (NODE_ENV=production webpack -p), and then add or remove some plugins based on that.

    EDIT: here is an example of what I’m doing, webpack-dashboard has an issue and so it needs to be included only in development

  5. I agree this is an issue. I spent several hour on it before I found out what is causing my problems 🙁
    There are many articles and repositories which depend on having NODE_ENV set in config file already.

  6. The key part for me was to understand that environment variables are not available in the webpack build process unless specified. That’s why we need the following line from @fab1an‘s great example :

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

    ….which can be stated more clearly using the EnvironmentPlugin, which directly passes environment variables to the build:

    ...
            new webpack.EnvironmentPlugin(['NODE_ENV']),
    ...
    
  7. Currently I’m handling this issue with webpack -p --env production.

    And then in webpack.config.js:

    module.exports = function(env) {
        // return env-specific configuration
    }

    I do agree the -p and --env production is a bit repetitive.

  8. It seems that most people here thinks that webpack -p is mandatory to do a production build, but am I the only one thinking it should not be this way?

    Not all are running webpack for production via the CLI, but programmatically via node. Shouldnt webpack -p be the same as running webpack with NODE_ENV=production?

  9. -p automatically adds

            new webpack.DefinePlugin({
                'process.env': {
                    'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
                }
            }),
           new webpack.optimize.UglifyJsPlugin()
    

    as plugins. It is not mandatory, it just enables those plugins for you for convenience.

    Because of the DefinePlugin, process.env.NODE_ENV will be replaced in your source files, just like if you had used DefinePlugin in your config by hand. It will not set the node environment variable process.env.NODE_ENV in your webpack config, as the webpack config is run directly by node.

    Basically, what you want to do is NODE_ENV=production webpack -p all the time. https://github.com/jacobmischka/coyote-grill/blob/master/package.json#L10

  10. In order, to determine if I am in development or production mode I use the following code in my webpack.config.js:

    // detect if webpack bundle is being processed in a production or development env
    let isDevelopmentMode = !(require('yargs').argv.p || false);

    then I can use it like:

        plugins: [
            new webpack.DefinePlugin({
                __DEBUG__: JSON.stringify(isDevelopmentMode)
            }),
        ]

    I hope it helps for someone looking for an alternative.

  11. I do the following:

    "build": "webpack --env production",

    and then in the webpack config:

    const path = require('path');
    const ExtractTextPlugin = require('extract-text-webpack-plugin');
    const BabiliPlugin = require('babili-webpack-plugin');
    
    const plugins = [
      new ExtractTextPlugin({
        filename: './bundle.css',
        allChunks: true,
      }),
    ];
    
    module.exports = function webpackStuff(env) {
      if (env === 'production') plugins.push(new BabiliPlugin());
    
      return { /* the rest of your config goes here */ };
    };

    Now I just do npm run build and everything is minified! 🎉

  12. The second argument of your config function contains webpack calling options. This is undocumented feature, but might be useful, anyway.

    module.exports = (env = {}, args = {}) => {
        console.log(args);
        // E.g. args.bail and args.p are true for webpack -p --bail
        ...
    };
  13. Wanting -p to set NODE_ENV to “production” is a bizarre request. -p indicates a production build, while NODE_ENV === "production" indicates a [runtime] production environment. I’ve never understood why devs tie these things together. I might want to test my production build in a local dev environment, in which case I now have to spoof NODE_ENV at build time. Unless you’re actually using Webpack in a runtime production environment, I’m not sure why you’d want your config to rely on NODE_ENV at all. It seems like it would be mixing two entirely unrelated concerns.

  14. I finally settled on the EnvironmentConfig’s defaulting behavior as in:

        plugins: [
            new webpack.EnvironmentPlugin({
                NODE_ENV: 'development'
            })
        ]
    

    This just sets the default NODE_ENV value if not already defined.

    If you also set it on the command line, as in NODE_ENV=production webpack ..., the command line wins. To me, that is intuitive and desirable.

    Yes it’s confusing to write NODE_ENV=production webpack -p ... as many have pointed out, but when the light bulb finally went on I realized this is really two different concepts.

  15. The solution is simple: rename -p to -o for optimize, which is exactly what this does. That way we can disassociate this command with the concept of production/environment variables. It should never have been called -p anyway.

  16. Why not using:

    "scripts": {
      "build": "webpack --env development",
      "build:production": "webpack --env production"
    }

    And inside webpack.config.js:

    module.exports = env => ({
       /* ... */
       plugins: [
         new webpack.DefinePlugin({
           'process.env': {
             NODE_ENV: JSON.stringify(env),
           },
         }),
       ],
       /* ... */
    })
    
  17. Please clarify your documentation then. (Add an additional mark, stating that it does not set it for the config itself)

    https://webpack.js.org/guides/production/#cli-alternatives

    states that -p sets both flags. But in webpack 3.9.1 it still only sets this variable for packages run by webpack and not the webpack config itself.

    Why use it?

    See my repo: https://github.com/SamanthaAdrichem/webpack-3.9.1-splitted-config-angular/

    i’m using it to load separate development and production configs -p now feels like a useless argument

  18. @mittalyashu It’s in webpack --help:

    -p           shortcut for --optimize-minimize --define
                   process.env.NODE_ENV="production"
    
      --optimize-minimize        Minimize javascript and switches loaders to
                                 minimizing
    
  19. I sometimes use NODE_ENV outside the context of bundling. Is there a command-line flag or configuration setting to prevent --mode from changing NODE_ENV?

    const fooConfig = {
      test: 'foo',
      local: 'Foo',
      sandbox: 'fooo',
      dev: 'FoOoOo',
      prod: 'FOO'
    }
    
    console.log(fooConfig[process.env['NODE_ENV']])
    
    $ NODE_ENV=dev node foo.js 
    FoOoOo
    
    
    $ webpack --mode development --entry ./foo.js -o ./fooBundle.js
    Hash: 82c0f8c800e30479245d
    Version: webpack 4.1.0
    ...
    
    $ NODE_ENV=dev node fooBundle.js
    undefined
    
    

    Update: yes there is. 🎉 😄

    {
      ...
      optimization: {
        nodeEnv: process.env.NODE_ENV
      }
      ...
    }
    

    Update 2: this is still bad, do this:

    This should make it so webpack leaves process.env.NODE in your bundled code rather than resolving it to whatever NODE_ENV is at compile-time, which is what you’d want in the dumb example above.

    {
      ...
      optimization: {
        nodeEnv: false
      }
      ...
    }
    

Comments are closed.