Awesome Webpack Perf
A curated list of webpack tools and plugins that help make the web faster
Contents
- Built-in stuff
- JS minifiers
- CSS
- CSS-in-JS
- Images
- Fonts
- Gzip/Brotli
- Service workers
<link rel>
and<script async>
- Prerendering
- Progressive web apps (PWA)
- Analysis tools
- Build-time audit tools
- Other web performance lists
Built-in stuff
mode: 'production'
in the webpack config enables the common production optimizationsoptimization.splitChunks
in the webpack config enables splitting one bundle into smaller chunks. This helps to load less JS for each page and cache better
JS minifiers
JS minifiers are tools that make JS payloads smaller.
uglifyjs-webpack-plugin
– Uglify is an ES5 minifierterser-webpack-plugin
– Terser is a fork of Uglify that has support for ES2015+. Ships with webpackbabel-minify-webpack-plugin
– Babel Minify is a minifier built in the Babel pipeline. It supports all syntax Babel supportsclosure-webpack-plugin
– Closure Compiler is a minifier developed by Google. It has several advanced optimizations that are unsafe for some apps but compress better
CSS
Minifiers
CSS minifiers are tools that make the volume of CSS smaller.
There’re three popular competing CSS minifiers: CSSO, CSS Nano and Clean CSS. They’re mostly similar in the compression quality and supported features, so if you’re picking one, just choose the one you prefer more.
-
csso-loader
postcss-csso
is a PostCSS plugin that can be used withpostcss-loader
csso-webpack-plugin
only works when you use a CSS extraction plugin. However, it compresses CSS better than the loader – e.g., it can merge rules from multiple source files
-
cssnano
is a PostCSS plugin that can be used withpostcss-loader
optimize-css-assets-webpack-plugin
, technically, works with any minifier, but ships (and works best) withcssnano
.
This plugin only works when you use a CSS extraction plugin. However, it compresses CSS better than the loader – e.g., it can merge rules from multiple source files
-
clean-css-loader
postcss-clean
is a PostCSS plugin that can be used withpostcss-loader
Other optimizers
purgecss-webpack-plugin
analyzes the app code and styles and removes CSS rules that aren’t used anywhere. Works great with CSS frameworks like Bootstrap
Extraction plugins
By default (with a simple style-loader
), all styles imported in the app are added into the JS bundle. CSS extraction plugins help to move these styles into a separate .css
file – which helps with faster rendering and better caching.
mini-css-extract-plugin
is the de-facto default solution for extracting styles in modern webpackextract-text-webpack-plugin
was the most popular plugin for extracting styles in webpack 1-3extract-css-chunks-webpack-plugin
has the same API asmini-css-extract-plugin
but offers better hot module replacement support
Critical CSS plugins
Critical CSS is an approach for rendering the site faster. With Critical CSS, for each page, you extract the rules needed for the initial render and inline them. Then, you load the remaining styles asynchronously. TODO: link to more details
html-critical-webpack-plugin
runs thecritical
tool on every webpack build. Uses a headless browser, returns styles only for the above-the-fold contentcritters-webpack-plugin
renders HTML in a JSDom environment on every webpack build. Doesn’t use a headless browser (= less heavy); returns all styles needed by the page, not only the above-the-fold ones (= may fix somehtml-critical-webpack-plugin
glitches)isomorphic-style-loader
helps to extract critical styles during server-side rendering
CSS-in-JS
CSS-in-JS libraries typically provide Critical CSS support out of the box and need fewer manual optimizations. However, they still need minification.
Minification
minify-cssinjs-loader
works with all CSS-in-JS libraries thanks to regex-based matching. Does basic compression of style strings- Library-specific Babel plugins. Many popular CSS-in-JS libraries have Babel plugins specifically created for them. They typically do a better job at optimization:
Images
Image compression tools
All the tools below use imagemin
and imagemin plugins for optimizing images, so they typically result in a similar level of compression.
You should prefer plugins over loaders. Plugins will optimize images that were produced by other loaders or plugins, whereas loaders will only trigger for files from your source code.
Other tools
-
lqip-loader
generates low-quality image placeholders which you can use for lazy-loading images. Just like in Medium: -
webp-loader
converts images to webp -
responsive-loader
resizes one image to multiple various sizes. Works great with<img srcset>
or<picture>
-
svg-url-loader
generates 20-30% smallerdata
-urls for inline SVG images
Fonts
google-fonts-webpack-plugin
downloads Google Fonts to the build directory for self-hostingfontmin-webpack
minifies icon fonts to just what’s used
Gzip/Brotli
Gzip/Brotli compressors compress text so it’s smaller when served over the network.
Normally, this is done by a server like Apache or Nginx on runtime; but you might want to pre-build compressed assets to save the runtime cost.
compression-webpack-plugin
works for Gzip and Brotlibrotli-webpack-plugin
works for Brotli
Service workers
Both plugins below generate a service worker that prefetches all webpack assets in the background and adds offline support into the application:
workbox-webpack-plugin
prefetches all webpack assets in the background and makes the app ready for working offline. It is based on Google’sworkbox
library that simplifies common usages of service workersoffline-plugin
also prefetches all webpack assets in the background and makes the app ready for working offline. It falls back to AppCache in browsers that don’t support service workers
<link rel>
and <script async>
preload-webpack-plugin
preloads asynchronous chunks¹ with<link rel="preload">
or<link rel="prefetch">
html-webpack-preconnect-plugin
adds<link rel="preconnect">
for a separate domain (e.g., an API server)script-ext-html-webpack-plugin
addsasync
ordefer
attributes to bundle scripts
¹ Asynchronous chunks are chunks that are created when you use dynamic import()
Prerendering
Prerendering tools run an app during the build and return the HTML the app generates. This is an alternative to server-side rendering and helps to deliver the content to the user immediately – instead of making them wait until the bundle is loaded.
Progressive web apps (PWA)
webpack-pwa-manifest
generates amanifest.json
and resizes app icons for a PWA
Analysis tools
-
webpack-bundle-analyzer
generates a view of the bundle content. Use it to figure out what takes so much size in the bundle:(Animation credits:
webpack-bundle-analyzer
) -
source-map-explorer
also generates a view of the bundle contents. It’s less detailed thanwebpack-bundle-analyzer
but only needs a source map to run:(Image credits:
source-map-explorer
) -
Webpack Analyse shows all modules present in the bundle – and relationships between them. Use it to understand why a specific suspicious module is bundled:
-
Bundlephobia reports bundle sizes of JS libraries:
Build-time audit tools
-
webpack-dashboard
reports sizes of modules and warnings like duplicated files during development:(Image credits:
webpack-dashboard
) -
duplicate-package-checker-webpack-plugin
prints a warning if a bundle includes multiple versions of the same library:(Image credits:
duplicate-package-checker-webpack-plugin
)
Other web performance lists
- Awesome WPO – A curated list of Web Performance Optimization
- Webpack Libs Optimizations – A collection of Babel and webpack plugins to optimize the size of various popular libraries
Contribute
Contributions welcome! Read the contribution guidelines first.
License
To the extent possible under law, Ivan Akulov has waived all copyright and related or neighboring rights to this work.