Let’s say you’re doing some logging in main.js
for development:
// main.js
var logger = require('./logger');
logger();
// ...
And your webpack config is as follows:
// webpack.config.js
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
}
};
But given how webpack works, it bundles all required modules (see last 2 lines):
$ webpack --display-chunks
Hash: 9d1935249bd4e4d05276
Version: webpack 2.2.1
Time: 89ms
Asset Size Chunks Chunk Names
bundle.js 2.63 kB 0 [emitted] main
chunk {0} bundle.js (main) 44 bytes [entry] [rendered]
[0] ./logger.js 23 bytes {0} [built]
[1] ./main.js 21 bytes {0} [built]
So how can we ignore the logger
module in production? With a combination of webpack’s plugins.
IgnorePlugin
With IgnorePlugin, a regular expression can be tested to prevent the module from being generated:
// webpack.config.js
var webpack = require('webpack');
var isProduction = process.env.NODE_ENV === 'production';
var plugins = [];
if (isProduction) {
plugins.push(
/**
* IgnorePlugin will skip any require
* that matches the following regex.
*/
new webpack.IgnorePlugin(/logger/)
);
}
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
plugins: plugins
};
Now when you build the bundle, you’ll see that logger
is no longer included as a chunk:
$ webpack --display-chunks
Hash: 0dc6a44b438e4bff97d1
Version: webpack 2.2.1
Time: 67ms
Asset Size Chunks Chunk Names
bundle.js 2.69 kB 0 [emitted] main
chunk {0} bundle.js (main) 21 bytes [entry] [rendered]
[0] ./main.js 21 bytes {0} [built]
However, if you load your bundle in a webpage, you’ll receive the error:
Cannot find module "./logger"
This is because logger
is still being called in main.js
and webpack doesn’t know that any logic related to it should be removed.
Wouldn’t it be nice if you could doing something like this:
// main.js
if (isDevelopment) {
var logger = require('./logger');
logger();
}
// ...
And have webpack strip out the if statement when isDevelopment
is false?
That’s where DefinePlugin and UglifyJsPlugin comes in.
DefinePlugin
With DefinePlugin, you can create global constants that are injected at compile time. See post on how to do that.
Now you can use the global constant in main.js
:
// main.js
if (process.env.NODE_ENV === 'development') {
var logger = require('./logger');
logger();
}
// ...
UglifyJsPlugin
Finally with UglifyJsPlugin, you can eliminate the dead code when the if statement is false:
// webpack.config.js
var webpack = require('webpack');
var isProduction = process.env.NODE_ENV === 'production';
var plugins = [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV)
}
})
];
if (isProduction) {
plugins.push(
new webpack.IgnorePlugin(/redux-logger/)
);
plugins.push(
/**
* UglifyJS will compress the bundle and
* eliminate any dead code.
*/
new webpack.optimize.UglifyJsPlugin()
);
}
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
plugins: plugins
};
Now you can have separate builds for each environment:
$ NODE_ENV=development webpack --display-chunks
Hash: b7f5f05d03abe533ec77
Version: webpack 2.2.1
Time: 89ms
Asset Size Chunks Chunk Names
bundle.js 2.68 kB 0 [emitted] main
chunk {0} bundle.js (main) 121 bytes [entry] [rendered]
[0] ./logger.js 23 bytes {0} [built]
[1] ./main.js 98 bytes {0} [built]
$ NODE_ENV=production webpack --display-chunks
Hash: a8169341174e7bc6437a
Version: webpack 2.2.1
Time: 130ms
Asset Size Chunks Chunk Names
bundle.js 536 bytes 0 [emitted] main
chunk {0} bundle.js (main) 98 bytes [entry] [rendered]
[0] ./main.js 98 bytes {0} [built]