Webpack tricks
Just a small catalog of Webpack tips and tricks I've learned. These tricks work with Webpack v3 unless otherwise specified.
Table of contents
- Progress reporting
- Minification
- Multiple bundles
- Split app and vendor code
- Source maps (Webpack 1)
- Source maps (Webpack 2-3)
- Output CSS files
- Development mode
- Investigating bundle sizes
- Smaller React
- Smaller Lodash
- Requiring all files in a folder
- Clean up extract-text-webpack-plugin log
Progress reporting
Invoke Webpack with:
--progress --colors
Minification
Invoke Webpack with -p
for production builds. In Webpack 2, this also automatically sets process.env.NODE_ENV === 'production'
.
webpack -p
Multiple bundles
Export multiple bundles by setting the output to [name].js
. This example produces a.js
and b.js
.
module.exports = {
entry: {
a: './a',
b: './b'
},
output: { filename: '[name].js' }
}
Concerned about duplication? Use the CommonsChunkPlugin to move the common parts into a new output file.
plugins: [ new webpack.optimize.CommonsChunkPlugin('init.js') ]
<script src='init.js'></script>
<script src='a.js'></script>
Split app and vendor code
Use CommonsChunkPlugin to move vendor code into vendor.js
.
var webpack = require('webpack')
module.exports = {
entry: {
app: './app.js',
vendor: ['jquery', 'underscore', ...]
},
output: {
filename: '[name].js'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin('vendor')
]
}
How this works:
- We make a
vendor
entry point and load it with some libraries - CommonsChunkPlugin will remove these libraries from
app.js
(because it appears in 2 bundles now) - CommonsChunkPlugin also moves the Webpack runtime into
vendor.js
Reference: Code splitting
Source maps (Webpack 1)
The best source maps option is cheap-module-eval-source-map
. This shows original source files in Chrome/Firefox dev tools. It's faster than source-map
and eval-source-map
.
// Webpack 1 only
const DEBUG = process.env.NODE_ENV !== 'production'
module.exports = {
debug: DEBUG ? true : false,
devtool: DEBUG ? 'cheap-module-eval-source-map' : 'hidden-source-map'
}
Your files will now show up in Chrome Devtools as webpack:///foo.js?a93h
. We want this to be cleaner like webpack:///path/to/foo.js
.
output: {
devtoolModuleFilenameTemplate: 'webpack:///[absolute-resource-path]'
}
Reference: devtool documentation
Source maps (Webpack 2-3)
The best source maps option is cheap-module-source-map
. The cheap-module-eval-source-map strategy no longer shows correct traces in Chrome/Firefox.
// Webpack 2 only
const DEBUG = process.env.NODE_ENV !== 'production'
module.exports = {
devtool: DEBUG ? 'cheap-module-source-map' : 'hidden-source-map'
}
If you're using extract-text-webpack-plugin, use 'source-map'
instead. CSS sourcemaps won't work otherwise.
// Only if you're using extract-text-webpack-plugin
module.exports = {
devtool: DEBUG ? 'source-map' : 'hidden-source-map'
}
Your files will now show up in Chrome Devtools as webpack:///foo.js?a93h
. We want this to be cleaner like webpack:///path/to/foo.js
.
output: {
devtoolModuleFilenameTemplate: 'webpack:///[absolute-resource-path]'
}
Reference: devtool documentation
Output CSS files
This is complicated, and the guide can be found here.
Development mode
Want to have certain options only appear in development mode?
const DEBUG = process.env.NODE_ENV !== 'production'
// Webpack 1
module.exports = {
debug: DEBUG ? true : false,
devtool: DEBUG ? 'cheap-module-eval-source-map' : 'hidden-source-map'
}
// Webpack 2
module.exports = {
devtool: DEBUG ? 'cheap-module-source-map' : 'hidden-source-map'
}
Webpack 1: Be sure to invoke Webpack as env NODE_ENV=production webpack -p
when building your production assets.
Webpack 2: Invoke Webpack as webpack -p
when building your production assets. NODE_ENV
is automatically set by Webpack.
Investigating bundle sizes
Want to see what dependencies are the largest? You can use webpack-bundle-size-analyzer.
$ yarn global add webpack-bundle-size-analyzer
$ ./node_modules/.bin/webpack --json | webpack-bundle-size-analyzer
jquery: 260.93 KB (37.1%)
moment: 137.34 KB (19.5%)
parsleyjs: 87.88 KB (12.5%)
bootstrap-sass: 68.07 KB (9.68%)
...
If you're generating source maps (you should), you can also use source-map-explorer, which also works outside of Webpack.
$ yarn global add source-map-explorer
$ source-map-explorer bundle.min.js bundle.min.js.map
Reference: webpack-bundle-size-analyzer, source-map-explorer
Smaller React
React will build dev tools by default. You don't need this in production. Use the EnvironmentPlugin to make these dev tools disappear. This saves you around 30kb.
plugins: [
new webpack.EnvironmentPlugin({
NODE_ENV: 'development'
})
]
Webpack 1: Be sure to invoke Webpack as env NODE_ENV=production webpack -p
when building your production assets.
Webpack 2: Invoke Webpack as webpack -p
when building your production assets. NODE_ENV
is automatically set by Webpack.
Reference: EnvironmentPlugin documentation
Smaller Lodash
Lodash is very useful but usually we only need a small part of its full functionality. lodash-webpack-plugin can help you shrink the lodash build by replacing feature sets of modules with noop, identity, or simpler alternatives.
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
const config = {
plugins: [
new LodashModuleReplacementPlugin({
path: true,
flattening: true
})
]
};
This may save you >10kb depending on how much you use lodash.
Requiring all files in a folder
Ever wanted to do this?
require('./behaviors/*') /* Doesn't work! */
Use require.context.
// http://stackoverflow.com/a/30652110/873870
function requireAll (r) { r.keys().forEach(r) }
requireAll(require.context('./behaviors/', true, /\.js$/))
Reference: require.context
Clean up extract-text-webpack-plugin log
If you're seeing this in your debug log when using extract-text-webpack-plugin:
Child extract-text-webpack-plugin:
+ 2 hidden modules
Child extract-text-webpack-plugin:
+ 2 hidden modules
Child extract-text-webpack-plugin:
+ 2 hidden modules
Turn it off using stats: { children: false }
.
/* webpack.config.js */
stats: {
children: false,
},
Reference: extract-text-webpack-plugin#35