The bigger your ES application becomes the longer it takes to webpack to build a bundle. No surprise here.
What is unusual (at least it was to me) is that webpack cache doesn’t work like you expect it to work. Even in case of bundling node_modules, which are very rarely changed. No matter if you move it into separate bundle with CommonsChunkPlugin — it simply builds node_modules all the time.
Below I will explain how to improve this at both your local working environment and at third parties, like CI.
The reason it doesn’t help is that webpack cache is only aimed for improving performance of incremental builds. Its purpose is to speed up updates in watch mode, not to start up quickly. So it will not solve the problem.
Not just cache, but has caching option which is enabled by default. What HappyPack actually does is launching multiple threads of build process.
Sounds great. But in real life it didn’t show good performance, even worse — we start to experience issues with improperly validated cache, not pretty often, but still annoying.
I admit we just didn’t play enough with its config, but someone who did achieved good results. Massive logic under the hood of HappyPack must confirm my thoughts. But next two solutions allowed us to have better results with less configuration.
Average time saving— 25%
With DLL webpack plugin you can build node_modules just once and forget about it until you change anything in node_modules again. In next builds Webpack will reuse modules from compiled dll-bundle.
The process is a bit complicated but it’s worth it. You first build your dll-bundle and manifest.json with separate webpack config and DllPlugin. And then apply DLLReferencePlugin to reuse dll-bundle in any other webpack build.
Good news is that it not only works with node_modules. You can move any part of your app into dll-bundle. Found a code/module rarely changed? Move it into dll-bundle, save your time!
The only caveat in using DllPlugin is that if you import from npm package it is not aware of package.json:main and keeps full path to imported file. What it means for you is that after building dll-bundle, in manifest.json instead of import paths like redux you will find ./redux/es/index.js. This will break your app import paths. To solve the issue pass modified manifest.json content to DLLReferencePlugin.
Here comes the cavalry!
Average time saving — 70% (!)
It started in this thread while discussing issues with webpack cache. And led to creation of the caching plugin which brings amazing performance gain to build process. The guy who created it went deeply into webpack source to find a solution for productive caching. You definitely should read the thread.
HardSourcePlugin with almost default configuration speed up our builds from 40s down to ~10s in a large application. Some of us with good hardware even build the same app in ~2s. And so far we didn’t have any serious issue with HardSourcePlugin.
Combining DllPLugin with HardSourcePlugin lets us forget about long builds. Seriously. That’s true for local developers environment and somehow true for third parties, like CI.
The problem with CI is that application code may change significantly between builds and thus increase the chance of invalidation issues. Resolving such an issue will make you clean up the cache dir on CI server, and start up build process again, without cache. It takes much time.
I don’t know how often we will meet invalidation issues if we run HardSourcePlugin with CI and I’m very curious to get to know. We will test it in real life conditions and in case of good results I will write on an article explaining setup for all popular CI.
Ottofeller is the software development company specialising in front end of complex web applications and promising cutting edge technologies.