Webpack's performance out of the box is often enough for small projects. That said, it begins to hit limits as your project grows in scale, and it's a frequent topic in webpack's issue tracker.
There are a couple of ground rules when it comes to optimization:
Sometimes optimizations come with a cost. You could, for example, trade memory for performance or end up making your configuration more complicated.
If you hit memory limits with webpack, you can give it more memory with node --max-old-space-size=4096 node_modules/.bin/wp --mode development
kind of invocation. Size is given in megabytes, and in the example you would give 4 gigabytes of memory to the process.
As discussed in the previous chapter, generating stats can be used to measure build time. webpack.debug.ProfilingPlugin and cpuprofile-webpack-plugin are able to emit the timings of plugin execution as a file you can pass to Chrome Inspector. The latter generates a flame graph as well.
Webpack uses only a single instance by default, meaning you aren't able to benefit from a multi-core processor without extra effort. This is where thread-loader and third-party solutions, such as parallel-webpack.
webpack-plugin-ramdisk writes the build output to a RAM disk and it can help during development and in case you have to perform many successive builds.
parallel-webpack allows you to parallelize webpack configuration in two ways. Assuming you have defined your webpack configuration as an array, it can run them in parallel. In addition to this, the tool can generate builds based on given variants.
Variants allow you to generate both production and development builds at once. They let you to create bundles with different targets to make them easier to consume depending on the environment. Variants can be used to implement feature flags when combined with DefinePlugin
as discussed in the Environment Variables chapter.
parallel-webpack can be used by installing it to your project as a development dependency and then running webpack through parallel-webpack
command.
Specific lower-level optimizations can be nice to know. The key is to allow webpack to perform less work. Consider the examples below:
process
which in turn will bloat your bundle if polyfilled. See webpack documentation for the default values.cache.type = "filesystem"
. To invalidate it on configuration change, you should set cache.buildDependencies.config = [__filename]
. Webpack handles anything watched by the build automatically including plugins, loaders, and project files.Loaders have their optimizations as well:
include
or exclude
with JavaScript specific loaders. Webpack traverses node_modules
by default, and executes babel-loader over the files unless it has been configured correctly.Rebundling times during development can be improved by pointing the development setup to a minified version of a library, such as React. In React's case, you lose propType
-based validation but if speed is paramount, this technique is worth it.
module.noParse
accepts a RegExp or an array of RegExps. In addition to telling webpack not to parse the minified file you want to use, you have to point react
to it by using resolve.alias
. The idea is discussed in detail in the Consuming Packages chapter.
You can encapsulate the idea within a function:
exports.dontParse = ({ name, path }) => ({
module: { noParse: [new RegExp(path)] },
resolve: { alias: { [name]: path } },
});
To use the function, you call it as follows:
dontParse({
name: "react",
path: path.resolve(
__dirname, "node_modules/react/cjs/react.production.min.js",
),
}),
After this change, the application should be faster to rebuild, depending on the underlying implementation. The technique can also be applied to production.
Given module.noParse
accepts a regular expression if you wanted to ignore all *.min.js
files, you could set it to /\.min\.js/
.
Not all modules supportmodule.noParse
. They should not have a reference torequire
,define
, or similar, as that leads to anUncaught ReferenceError: require is not defined
error.
There are various webpack 4 specific tricks to improve performance:
output.futureEmitAssets
is set, webpack 5 related logic is enabled. Based on Shawn Wang, it reduces memory usage and improves situation.stats.toJson
using ts-loader with experimentalWatchApi
and setting output.pathinfo
to false
.optimization
property and its splitChunks
, removeAvailableModules
, and removeEmptyChunks
properties to false
can improve performance in the development
mode.You can optimize webpack's performance in multiple ways. Often it's a good idea to start with more accessible techniques before moving to more involved ones. The exact methods you have to use depend on the project.
To recap:
The official build performance guide and Web Fundamentals by Google have more tips.
This book is available through Leanpub (digital), Amazon (paperback), and Kindle (digital). By purchasing the book you support the development of further content. A part of profit (~30%) goes to Tobias Koppers, the author of webpack.