119

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]
  }
};
Gilson PJ
  • 3,443
  • 3
  • 32
  • 53
  • 1
    Did you find an answer to your last question? "How to use these files? Currently I am using webpack-dev-server to run the application." – Randy Apr 27 '17 at 16:30

8 Answers8

80

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.

Scott Schupbach
  • 1,284
  • 9
  • 21
sandeep
  • 2,098
  • 1
  • 10
  • 13
  • 9
    ok thanks. my next doubt is how to run the production code? when i run the above command it creates some files in dist directory. ok it compiled successfully. now how to use these files? in development mode i used 'npm start' and its started. – Gilson PJ Jan 28 '16 at 11:28
  • If you go to your `src/server/bin/server`. Then you can figure out how it is serving the files and maybe change it. What i think it will be doing is running webpack to build files and then serve them. Have a look at code of this file. – sandeep Jan 28 '16 at 17:21
  • @Vikramaditya Could you help me with the scenario in http://stackoverflow.com/questions/40993795/msbuild-and-webpack – lohiarahul Dec 06 '16 at 12:17
  • @GilsonPJ did you figure out how to use these UI files ? – Randy Apr 27 '17 at 16:05
  • You need to install webpack first using `npm install webpack` – Peter Rader Sep 08 '17 at 14:14
46

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!

Gilson PJ
  • 3,443
  • 3
  • 32
  • 53
  • 8
    What do you mean in your last sentence? How to supply these codes? I know node.js builds a server in itself. But how can I run it after I have the file in the `./dist/` directory? – newguy Sep 05 '16 at 06:33
  • 6
    Just a note, adding the -p option on top of the uglifyJS plugin causes issues as it tries to uglify twice. Removing the -p cli option fixed these issues for me – timelfelt Sep 27 '16 at 18:01
  • 'NODE_ENV' is not recognized as an internal or external command, operable program or batch file. – Anton Duzenko Nov 17 '16 at 08:54
  • @AntonDuzenko `NODE_ENV` is an environement variable that is specified in the form of `NAME=value` and placed before the actual command name. It does not work on Windows command line how ever, only on Linux bash and possibly on mac, though I have not tried. – lanoxx Dec 06 '16 at 08:13
  • 2
    This should be the accepted answer, because no-one was saying how to serve the website **Now your UI code will be available in ./dist/ directory. Set your server to supply these UI code for the request. and you are done.!** – jperelli Feb 21 '17 at 15:15
  • 3
    I still don't get how to "Set your server to supply these UI code for the request. and you are done.". I understand what we want to do here but I just don't know how to do it – Randy Apr 27 '17 at 16:02
  • 2
    This does not work for Webpack 4. Also `mode: 'production' ` takes care of the `NODE_ENV` – Dennis Jun 24 '19 at 01:13
  • This is very outdated information. In modern versions of the webpack the [SplitChunksPlugin](https://webpack.js.org/plugins/split-chunks-plugin/) should be used instead of the `CommonChunkPlugin`. – Slava Fomin II Apr 15 '23 at 13:48
41

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 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.

Eirik Birkeland
  • 588
  • 5
  • 11
Vikramaditya
  • 5,444
  • 6
  • 34
  • 45
  • 1
    what does the 'common.js' part do on commonschuckplugin? that plugin is easily the hardest for me to grasp. – Echiban Feb 23 '16 at 18:25
  • 2
    CommonsChunkPlugin extracts the common code from all your chunks and put it in a separate file `common.js`. – Vikramaditya Feb 24 '16 at 07:07
  • 4
    This answer is no longer valid for webpack version 4 – Dennis Jun 24 '19 at 01:12
  • This is very outdated information. In modern versions of the webpack the [SplitChunksPlugin](https://webpack.js.org/plugins/split-chunks-plugin/) should be used instead of the `CommonChunkPlugin`. – Slava Fomin II Apr 15 '23 at 13:49
31

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)

Siyuan Jiang
  • 431
  • 4
  • 4
  • 2
    If you started to learn nodejs, expressjs etc things then I want to tell you. This question is advance level question. It's not only for How to run these files. It's for How to minimize (compress) production code and how to run that compressed code – Arpit Feb 27 '18 at 10:11
  • 2
    @Arpit Thanks for pointing this out. I am very new to this. I assumed once the compressed code is generated, the running method should be the same. – Siyuan Jiang Mar 19 '18 at 13:25
  • Thank you very much for this answer. Even though it is such a simple nodejs application it routing finally works on my application. Before that I tried to use a golang with a serve library but routing did not work with this solution. – ungarmichael Mar 15 '21 at 11:20
9

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.

Hayk Aghabekyan
  • 1,087
  • 10
  • 19
5

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
    })
  ],
Khalid Azam
  • 1,615
  • 19
  • 17
3

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

Matthias Sommer
  • 1,070
  • 13
  • 28
1

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

Sameer
  • 4,758
  • 3
  • 20
  • 41