Minifying
#
Since webpack 4, the production output gets minified using terser↗ by default. Terser is an ES2015+ compatible JavaScript-minifier. Compared to UglifyJS, the earlier standard for many projects, it’s a future-oriented option.
Although webpack minifies the output by default, it’s good to understand how to customize the behavior should you want to adjust it further or replace the minifier.
Minifying JavaScript
#
The point of minification is to convert the code into a smaller form. Safe transformations do this without losing any meaning by rewriting code. Good examples of this include renaming variables or even removing entire blocks of code based on the fact that they are unreachable (if (false)
).
Unsafe transformations can break code as they can lose something implicit the underlying code relies upon. For example, Angular 1 expects specific function parameter naming when using modules. Rewriting the parameters breaks code unless you take precautions against it in this case.
Modifying JavaScript minification process
#
In webpack, minification process is controlled through two configuration fields: optimization.minimize
flag to toggle it and optimization.minimizer
array to configure the process.
To tune the defaults, we’ll attach terser-webpack-plugin↗ to the project so that it’s possible to adjust it.
To get started, include the plugin to the project:
npm add terser-webpack-plugin -D
To attach it to the configuration, define a part for it first:
webpack.parts.js
const TerserPlugin = require("terser-webpack-plugin");
exports.minifyJavaScript = () => ({
optimization: { minimizer: [new TerserPlugin()] },
});
Hook it up to the configuration:
webpack.config.js
const productionConfig = merge([
parts.minifyJavaScript(),
...
]);
If you execute npm run build
now, you should see result close to the same as before.
sourceMap
flag. You should check terser-webpack-plugin documentation for further options.
terserOptions
with the related options to the plugin.
Speeding up JavaScript execution
#
Specific solutions allow you to preprocess code so that it will run faster. They complement the minification technique and can be split into scope hoisting, pre-evaluation, and improving parsing. It’s possible these techniques grow overall bundle size sometimes while allowing faster execution.
Scope hoisting
#
Since webpack 4, it applies scope hoisting in production mode by default. It hoists all modules to a single scope instead of writing a separate closure for each. Doing this slows down the build but gives you bundles that are faster to execute. Read more about scope hoisting↗ at the webpack blog.
stats.optimizationBailout
flag as true
to gain debugging information related to hoisting results.
Minifying HTML
#
If you consume HTML templates through your code using html-loader↗, you can preprocess it through posthtml↗ with posthtml-loader↗. You can use posthtml-minifier↗ to minify your HTML through it and posthtml-minify-classnames↗ to reduce the length of class names.
Minifying CSS
#
css-minimizer-webpack-plugin↗ is a plugin-based option that applies a chosen minifier on CSS assets. Using MiniCssExtractPlugin
can lead to duplicated CSS given it only merges text chunks. css-minimizer-webpack-plugin avoids this problem by operating on the generated result and thus can lead to a better outcome. The plugin uses cssnano↗ underneath.
Setting Up CSS minification
#
To get started, install css-minimizer-webpack-plugin first:
npm add css-minimizer-webpack-plugin -D
Like for JavaScript, you can wrap the idea in a configuration part:
webpack.parts.js
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
exports.minifyCSS = ({ options }) => ({
optimization: {
minimizer: [
new CssMinimizerPlugin({ minimizerOptions: options }),
],
},
});
minify
option. It accepts a function with the signature (data, inputMap, minimizerOptions) => <string>
.
Then, connect with the main configuration:
webpack.config.js
const productionConfig = merge([
parts.minifyJavaScript(),
parts.minifyCSS({ options: { preset: ["default"] } }),
...
]);
If you build the project now (npm run build
), you should notice that CSS has become smaller as it’s missing comments and has been concatenated:
⬡ webpack: Build Finished
⬡ webpack: assets by path *.js 129 KiB
asset vendor.js 126 KiB [emitted] [minimized] (name: vendor) (id hint: commons) 2 related assets
asset main.js 3.32 KiB [emitted] [minimized] (name: main) 2 related assets
asset 34.js 247 bytes [emitted] [minimized] 2 related assets
asset main.css 730 bytes [emitted] (name: main)
...
webpack 5.5.0 compiled successfully in 6388 ms
Compressing bundles
#
Compression techniques, such as gzip or brotli, can be used to reduce the file size further. The downside of using additional compression is that it will lead to extra computation on the client side but on the plus side you save bandwidth.
Often the compression setup can be done on server-side. Using webpack, it’s possible to perform preprocessing with compression-webpack-plugin↗.
Obfuscating output
#
To make it more tricky for third parties to use your code, use webpack-obfuscator↗. Although protecting code is difficult when it’s shared with the client, the code can be made much harder to use.
Conclusion
#
Minification is the most comfortable step you can take to make your build smaller. To recap:
- Minification process analyzes your source code and turns it into a smaller form with the same meaning if you use safe transformations. Specific unsafe transformations allow you to reach even smaller results while potentially breaking code that relies, for example, on exact parameter naming.
- Webpack performs minification in production mode using Terser by default.
- Besides JavaScript, it’s possible to minify other assets, such as CSS and HTML too. Minifying these requires specific technologies that have to be applied through loaders and plugins of their own.
You’ll learn to apply tree shaking against code in the next chapter.