Lessons Learned From a Year of Fighting With Webpack and Babel
Tags: react, javascript, webpack, babel
Published: 2018-12-25 21:08:08

---
title: Lessons Learned From a Year of Fighting With Webpack and Babel
published: true
description: Is your single page app not working on some browsers? Is your webpack build time taking ages? This article should help.
tags: react, javascript, webpack, babel 
---



I've been using React for more than a year now and a lot of the time things broke, slowed down our build speeds, and didn't work in the browsers I was transpiling for. I decided to share the lessons I've learned in the hopes they might help others out.

## Be very careful with importing large libraries

Trying to compile large libraries (like react-plotly or PDF libraries) can take your Webpack compile from seconds to 10 minutes+. If a package is slowing down your compile, consider using a CDN version. We simply used script tags, but there are Webpack plugins that can help with that too:

* [webpack-cdn-plugin](https://www.npmjs.com/package/webpack-cdn-plugin).
* [dynamic-cdn-webpack-plugin](https://www.npmjs.com/package/dynamic-cdn-webpack-plugin).

## Try to find a webpack plugin for your dependencies

Just importing packages like moment.js or lodash brings in a lot of bloat that you probably don't need. Try to import what you need only, or better yet find a webpack plugin that removes the unused things from your bundle, because [selective imports don't always work](https://github.com/react-bootstrap/react-bootstrap/issues/2683). As one example, there's [a webpack plugin](https://github.com/iamakulov/moment-locales-webpack-plugin) that removes a lot of the unnecessary bloat added by Moment.js.

Google actually has a [nice repository](https://github.com/GoogleChromeLabs/webpack-libs-optimizations) listing some common problematic dependencies.

## Inspect your bundle with Webpack bundle analyzer

![](https://thepracticaldev.s3.amazonaws.com/i/uw90hpp9pwc1xq132nl0.png)

[Webpack Bundle Analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer) is extremely helpful to see what exactly is going into your bundle. In the screenshot above, you'll notice that moment.js has lots of localization files that your app probably doesn't need. Webpack Bundle Analyzer can help you easily spot these issues.

## Add es-check to your CI pipeline early on

[es-check](https://github.com/dollarshaveclub/es-check) will help you find out which ES version your bundle is using, it's super useful to find out if you're somehow suddenly not producing ES5 anymore. Even if you're using Babel and browserslist, you might be importing a node module that's not even meant to be used in browsers, or even a package that's not being distributed as ES5. Add es-check to your continuous integration pipeline early on and it should help you find out if your bundle ever stops working with ES5, and that'll help you find which package is the culprit so you can then transpile it.

## Transpiling a node_module

We had imported a very simple package called [hex-rgb](https://github.com/sindresorhus/hex-rgb) that's not even meant for browsers and this tiny package made our bundle not ES5-compatible anymore. Such packages should go through Babel and be transpiled.

In your webpack config, your babel loader's exclude field probably looks like this: `/node_modules/` . We need to make a regex that excludes node_modules except the specific ones that should be transpiled:

```javascript
// Exclude all node modules except hex-rgb and another-package
/node_modules\/(?![hex\-rgb|another\-package])/
```

And once again, this might not be a good solution for large packages as it can drastically slow your build time and you might want to switch to a CDN version instead.

Follow [this issue](https://github.com/babel/babel-loader/issues/171) from the babel-loader repo to stay up to date on how to handle cases like this.

**Update** _(01 Feb 2018)_
I published a package called [are-you-es5](https://github.com/obahareth/are-you-es5) to help out more with this. It gives you easy to read output, and even builds the regex you need for transpiling those specific modules, check it out!

![](https://thepracticaldev.s3.amazonaws.com/i/2g93tl5ilquhwni8fmtw.png)

## Use Browserslist to specify your target browsers

[Browserslist](https://github.com/browserslist/browserslist) lets you specify which browsers to transpile for.

```
> 1%
ie >= 8
```

This simple configuration targets browsers with usage more than 1% global usage, and IE versions 8 and above.

## Use babel.config.js over .babelrc (for Babel ≥ 7.0)

Favor using `babel.config.js` to configure Babel over `.babelrc`. If you want to transpile node_modules (which is now becoming a very common case with webapps), then you should use `babel.config.js`.
`.babelrc` can be overridden by another `.babelrc` belonging to a node_module that you're transpiling and that can lead to all sorts of weird issues.

## Make your webpack-dev-server logging output friendlier

Change your [webpack-dev-server config](https://webpack.js.org/configuration/dev-server/) to this

```javascript
devServer: {
  noInfo: true,
  stats: 'minimal'
}
```

2. Add [WebpackBar](https://github.com/nuxt/webpackbar) to get much less-verbose, friendlier, and more concise output.

![](https://thepracticaldev.s3.amazonaws.com/i/4kjmpngvc7gtkbb6kfk0.png)

Note: The first configuration is meant to be combined with Webpack Bundle Analyzer, as it suppresses console output for things related to your bundle that Webpack Bundle Analyzer already shows. If you're not using Webpack Bundle Analyzer, don't apply the first step.

  
---
  

## What I hope to see

We need a lot of improvements in our tooling around this process. Most webpack and Babel configs exclude the `node_modules` folder (with good reason, compilation would take an insanely long time if they didn't!), but I personally feel this is an area where we need smarter tools. It would be quite convenient if everything "just worked" only by configuring Webpack, and Babel along with browserslist without having to dig through dependencies and the often unique problems they introduce to our build pipeline ourselves. The package.json file could be a good starting point towards this goal. There are a couple of things that if used could help tools determine if a package should be tranpiled or not:

* The [browser field](https://docs.npmjs.com/files/package.json#browser), this should be used instead of the main field if your package targets browsers. Meaning that we should at least get a warning if we specify that we target browsers in our package.json and we import a package that doesn't have the browser field in its package.json.
* The [engines field](https://docs.npmjs.com/files/package.json#engines), This is usually used to specify the node versions your package targets, but I honestly think it should also be used to specify ES versions, since a lot of NPM's usage is targeting browsers nowadays.
If a package doesn't have any of these fields and we specified that we target browsers and ES5 then we should:
  * Get a warning when we import it.
  * Have Webpack plugins that detect these packages and un-exclude them so they get transpiled automatically.

## Closing Notes

Webpack and Babel are awesome, this article isn't trying to say otherwise. We wouldn't be able to use a lot of things if it weren't for them, but the experience of using them together needs to get better. I faced many of these issues over the course of many months and understanding them/finding solutions was incredibly difficult (error messages don't exactly tell you what went wrong and searching for them doesn't always give relevant results), and I hope this article can act as the guide I had hoped to find back then.