3 ways to reduce webpack bundle size

Is performance your main concern with your webpack setup? Are you worried that your bundle is too big?

Then this post is for you!

Go through these three steps to get a quick overview of what to do to optimize your bundle size. I have listed them with increasing difficulty so that you can start at the top and hopefully get a quick win and then you can work your way down.

Easy: Run webpack in production mode

Make sure you run webpack in production mode. To do that, you run webpack with the -p flag, like this:

webpack -p

This little flag does these two things to optimize your bundle size:

  1. Enable minification using UglifyJs. It removes unnecessary white spaces, new lines, unreachable code, etc.
  2. Set the NODE_ENV to “production”. This tells some packages, like React, to not include debug code.

Medium: use an analyzer tool

There are many good tools to analyze your bundle. The best ones I have used are these two:

They work a bit differently but the output is the same: A nice visual representation of all the modules in your bundle. The output from source-map-explorer looks like this (image from the GitHub repo):

This visualization makes it possible for you to get a really nice overview of what is in your bundle. You can also compare sizes of components and dependencies.

How to analyze the output:

  • Are some dependencies larger than you thought? Could you replace them with a minimalistic or more specialized alternative or rewrite it yourself?
  • Are you using moment.js and have all timezones in the bundle, but are only using one or two? Here is how to fix it.
  • Are you using lodash? Then consider using lodash-webpack-plugin and/or babel-plugin-lodash
  • Would it make sense to split the bundle up, so that not every component and dependency is loaded on every page? Then continue reading 🙂

Hard: use code splitting

Code splitting means to split your bundle into smaller bundles.

Now you might ask yourself “Why would anyone want to do that? Isn’t that bad for mobile?”. It’s true that you want to reduce the number of new HTTP connections to increase performance on mobile. But the advantage to using code splitting is you can use more of browser cache and have more specialized bundles.

Splitting libraries to separate bundle

Your dependencies usually do not change as often as your production code. With code splitting, you can split your dependencies into a separate bundle. This bundle can be cached by your user’s browser for longer periods than your production code bundle.

A good guide for implementing this is available here. My post about what to do with the bundle files might also be useful for you.

CSS code splitting

Are you using CSS in JavaScript? Then you could extract the CSS to a separate JavaScript bundle or a CSS file. The advantage is the same as extracting the vendor file to separate bundle: the browser can cache it for longer periods.

Check out this guide if you are interested learning more.

Fetching bundles asynchronously

With webpack, you can split your bundle into many smaller bundles, and then the browser can automatically fetch the bundles needed asynchronously. This means the browser always only downloads the JavaScript code needed, and nothing more. It’s pretty cool, but also the most advanced technology in this post.

This guide is really good to learn how to get started.

Conclusion

There is a lot you can do to optimize your bundle size. Some things are quick to implement, and some things can take a lot longer time.

It is definitely worth looking into the more easy parts of optimizing webpack. You can get a lot out of just spending 30 minutes working with the first two points in this post.

  • David Gilbertson

    It’s probably worth noting that this is not correct if you’re using HTTP2: “It’s true that you want to reduce the number of new HTTP connections to increase performance on mobile”. A lot of providers now are HTTP2 out of the box (like this site, for example)

  • Here is an example of a TypeScript + React + Redux-saga + Auth0 + Webpack + code splitting (with long-term caching) set up: https://github.com/jch254/starter-pack/tree/typescript

  • Isn’t caching evil? the idea to load async on demand sounds more reasonable