Webpack how to build production code and how to use it

node.jsReactjsNpmWebpackWebpack Dev-Server

node.js Problem Overview


I am very new to webpack, I found that in production build we can able to reduce the size of overall code. Currently webpack builds around 8MB files and main.js around 5MB. How to reduce the size of code in production build? I found a sample webpack configurtion file from internet and I configured for my application and I run npm run build and its started building and it generated some files in ./dist/ directory.

  1. Still these files are heavy(same as development version)
  2. How to use these files? Currently I am using webpack-dev-server to run the application.

package.json file

{
  "name": "MyAPP",
  "version": "0.1.0",
  "description": "",
  "main": "src/server/server.js",
  "repository": {
    "type": "git",
    "url": ""
  },
  "keywords": [
  ],
  "author": "Iam",
  "license": "MIT",
  "homepage": "http://example.com",
  "scripts": {
    "test": "",
    "start": "babel-node src/server/bin/server",
    "build": "rimraf dist && NODE_ENV=production webpack --config ./webpack.production.config.js --progress --profile --colors"
  },
  "dependencies": {
    "scripts" : "", ...
  },
  "devDependencies": {
    "scripts" : "", ...
  }
}

webpack.config.js

var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var public_dir = "src/frontend";
var ModernizrWebpackPlugin = require('modernizr-webpack-plugin');

module.exports = {
  devtool: 'eval-source-map',
  entry: [
    'webpack-hot-middleware/client?reload=true',
    path.join(__dirname, public_dir , 'main.js')
  ],
  output: {
    path: path.join(__dirname, '/dist/'),
    filename: '[name].js',
    publicPath: '/'
  },
  plugins: [
    plugins
  ],
  module: {
    loaders: [loaders]
  }
};

webpack.production.config.js

var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var public_dir = "src/frontend";
var ModernizrWebpackPlugin = require('modernizr-webpack-plugin');
console.log(path.join(__dirname, 'src/frontend' , 'index.html'));

module.exports = {
  devtool: 'eval-source-map',
  entry: [
    'webpack-hot-middleware/client?reload=true',
    path.join(__dirname, 'src/frontend' , 'main.js')
  ],
  output: {
    path: path.join(__dirname, '/dist/'),
    filename: '[name].js',
    publicPath: '/'
  },
  plugins: [plugins],
  resolve: {
    root: [path.resolve('./src/frontend/utils'), path.resolve('./src/frontend')],
    extensions: ['', '.js', '.css']
  },

  module: {
    loaders: [loaders]
  }
};

node.js Solutions


Solution 1 - node.js

You can add the plugins as suggested by @Vikramaditya. Then to generate the production build. You have to run the the command

NODE_ENV=production webpack --config ./webpack.production.config.js

If using babel, you will also need to prefix BABEL_ENV=node to the above command.

Solution 2 - node.js

After observing number of viewers to this question I decided to conclude an answer from Vikramaditya and Sandeep.

To build the production code the first thing you have to create is production configuration with optimization packages like,

  new webpack.optimize.CommonsChunkPlugin('common.js'),
  new webpack.optimize.DedupePlugin(),
  new webpack.optimize.UglifyJsPlugin(),
  new webpack.optimize.AggressiveMergingPlugin()

Then in the package.json file you can configure the build procedure with this production configuration

"scripts": {
    "build": "NODE_ENV=production webpack --config ./webpack.production.config.js"
},

now you have to run the following command to initiate the build

npm run build

As per my production build configuration webpack will build the source to ./dist directory.

Now your UI code will be available in ./dist/ directory. Configure your server to serve these files as static assets. Done!

Solution 3 - node.js

Use these plugins to optimize your production build:

  new webpack.optimize.CommonsChunkPlugin('common'),
  new webpack.optimize.DedupePlugin(),
  new webpack.optimize.UglifyJsPlugin(),
  new webpack.optimize.AggressiveMergingPlugin()

> I recently came to know about [compression-webpack-plugin][1] which gzips your output bundle to reduce its size. Add this as well in the above listed plugins list to further optimize your production code.

new CompressionPlugin({
      asset: "[path].gz[query]",
      algorithm: "gzip",
      test: /\.js$|\.css$|\.html$/,
      threshold: 10240,
      minRatio: 0.8
})

Server side dynamic gzip compression is not recommended for serving static client-side files because of heavy CPU usage. [1]: https://github.com/webpack/compression-webpack-plugin

Solution 4 - node.js

Just learning this myself. I will answer the second question:

  1. How to use these files? Currently I am using webpack-dev-server to run the application.

Instead of using webpack-dev-server, you can just run an "express". use npm install "express" and create a server.js in the project's root dir, something like this:

var path = require("path");
var express = require("express");

var DIST_DIR = path.join(__dirname, "build");
var PORT = 3000;
var app = express();

//Serving the files on the dist folder
app.use(express.static(DIST_DIR));

//Send index.html when the user access the web
app.get("*", function (req, res) {
  res.sendFile(path.join(DIST_DIR, "index.html"));
});

app.listen(PORT);

Then, in the package.json, add a script:

"start": "node server.js"

Finally, run the app: npm run start to start the server

A detailed example can be seen at: https://alejandronapoles.com/2016/03/12/the-simplest-webpack-and-express-setup/ (the example code is not compatible with the latest packages, but it will work with small tweaks)

Solution 5 - node.js

You can use argv npm module (install it by running npm install argv --save) for getting params in your webpack.config.js file and as for production you use -p flag "build": "webpack -p", you can add condition in webpack.config.js file like below

plugins: [
    new webpack.DefinePlugin({
        'process.env':{
            'NODE_ENV': argv.p ? JSON.stringify('production') : JSON.stringify('development')
        }
    })
]

And thats it.

Solution 6 - node.js

This will help you.

plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        // This has effect on the react lib size
        'NODE_ENV': JSON.stringify('production'),
      }
    }),
    new ExtractTextPlugin("bundle.css", {allChunks: false}),
    new webpack.optimize.AggressiveMergingPlugin(),
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.UglifyJsPlugin({
      mangle: true,
      compress: {
        warnings: false, // Suppress uglification warnings
        pure_getters: true,
        unsafe: true,
        unsafe_comps: true,
        screw_ie8: true
      },
      output: {
        comments: false,
      },
      exclude: [/\.min\.js$/gi] // skip pre-minified libs
    }),
    new webpack.IgnorePlugin(/^\.\/locale$/, [/moment$/]), //https://stackoverflow.com/questions/25384360/how-to-prevent-moment-js-from-loading-locales-with-webpack
    new CompressionPlugin({
      asset: "[path].gz[query]",
      algorithm: "gzip",
      test: /\.js$|\.css$|\.html$/,
      threshold: 10240,
      minRatio: 0
    })
  ],

Solution 7 - node.js

In addition to Gilson PJ answer:

 new webpack.optimize.CommonsChunkPlugin('common.js'),
 new webpack.optimize.DedupePlugin(),
 new webpack.optimize.UglifyJsPlugin(),
 new webpack.optimize.AggressiveMergingPlugin()

with

"scripts": {
    "build": "NODE_ENV=production webpack -p --config ./webpack.production.config.js"
},

cause that the it tries to uglify your code twice. See https://webpack.github.io/docs/cli.html#production-shortcut-p for more information.

You can fix this by removing the UglifyJsPlugin from plugins-array or add the OccurrenceOrderPlugin and remove the "-p"-flag. so one possible solution would be

 new webpack.optimize.CommonsChunkPlugin('common.js'),
 new webpack.optimize.DedupePlugin(),
 new webpack.optimize.UglifyJsPlugin(),
 new webpack.optimize.OccurrenceOrderPlugin(),
 new webpack.optimize.AggressiveMergingPlugin()

and

"scripts": {
    "build": "NODE_ENV=production webpack --config ./webpack.production.config.js"
},

Solution 8 - node.js

If you have a lot of duplicate code in your webpack.dev.config and your webpack.prod.config, you could use a boolean isProd to activate certain features only in certain situations and only have a single webpack.config.js file.

const isProd = (process.env.NODE_ENV === 'production');

 if (isProd) {
     plugins.push(new AotPlugin({
      "mainPath": "main.ts",
      "hostReplacementPaths": {
        "environments/index.ts": "environments/index.prod.ts"
      },
      "exclude": [],
      "tsConfigPath": "src/tsconfig.app.json"
    }));
    plugins.push(new UglifyJsPlugin({
      "mangle": {
        "screw_ie8": true
      },
      "compress": {
        "screw_ie8": true,
        "warnings": false
      },
      "sourceMap": false
    }));
  }

By the way: The DedupePlugin plugin was removed from Webpack. You should remove it from your configuration.

UPDATE:

In addition to my previous answer:

If you want to hide your code for release, try enclosejs.com. It allows you to:

  • make a release version of your application without sources
  • create a self-extracting archive or installer
  • Make a closed source GUI application
  • Put your assets inside the executable

You can install it with npm install -g enclose

Solution 9 - node.js

Latest answer including Webpack 5

For Webpack (version not remember)

NODE_ENV=production webpack --config ./webpack.production.config.js

For Webpack <4

plugins: [
    new webpack.DefinePlugin({
        'process.env':{
            'NODE_ENV': JSON.stringify('production')
                        //for development -> JSON.stringify('development')
        }
    })
]

For webpack >=4 (Including webpack 5) - Specify mode

 module.exports = {
   mode: 'production', //for development -> development
   devtool: 'inline-source-map',
   ...
 };

Quote from Webpack's official website > Since webpack v4, specifying mode automatically configures > DefinePlugin for you

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGilson PJView Question on Stackoverflow
Solution 1 - node.jssandeepView Answer on Stackoverflow
Solution 2 - node.jsGilson PJView Answer on Stackoverflow
Solution 3 - node.jsVikramadityaView Answer on Stackoverflow
Solution 4 - node.jsSiyuan JiangView Answer on Stackoverflow
Solution 5 - node.jsHayk AghabekyanView Answer on Stackoverflow
Solution 6 - node.jsKhalid AzamView Answer on Stackoverflow
Solution 7 - node.jsPutzi SanView Answer on Stackoverflow
Solution 8 - node.jsMatthias SommerView Answer on Stackoverflow
Solution 9 - node.jsSameerView Answer on Stackoverflow