Migrate your app to Babel 7 — A case study

Veronica Mihai
Busuu Tech
Published in
4 min readMay 8, 2019

--

Different projects setup

At the end of the past quarter, January — March 2019, here in the front-end team at busuu, we have decided to align the babel setup throughout all of our projects. There are four that we own in the front-end team and an additional one that is shared with the backend team. All of them have different setups (Gulp or Webpack 4.0) and use different technologies (AngularJS, React, plain JS). They are also using different babel versions and presets making it confusing to know what can and can’t be used in terms of ES6 functionalities when switching from one project to another. Therefore our goal was to align the babel versions and presets across all apps to ensure a consistent javascript features support .

Choosing the right Babel version

Throughout our projects, we have a mix of babel-preset-env, babel-preset-react, babel-preset-es3, es2015-mod, babel-preset-es2015, babel-preset-stage-3 with minor variations of babel-core 6.24.0.

There are quite a few substantial changes and improvements starting with Babel 7.0 that can speed up the process of finding just the right setup for your project. I’ve listed below a few of the differences between previous versions of Babel and Babel 7.0.

Before Babel 7.0

  • You have stage-0stage-3 presets for JS features in different proposal stages
  • You have babel-preset-es201x presets for every JS release

For polyfilling you can use

  • babel-preset-env which contains a default selection of polyfills and allows you to manually list any other plugins and polyfills that you might need. You can also include default polyfills for specifics browsers through the targets.browsers config option.
  • babel-polyfill that includes all the JS polyfills and really bloats your bundle with polyfills for features you might not even be using in your code.

With Babel 7.0

  • stage-0stage-3 have been deprecated (more about this here) and split into two core-js packages ( more about it here).
  • babel-preset-es201x presets have been unified into @babel/preset-env.
  • There is experimental support for useBuiltIn:’usage’ in @babel/preset-env — this allows you to include polyfills/plugins by based on your source code and the supported browsers in the targets config property.

core-js

Corejs is the package where babel includes the polyfills from. There are two versions, core-js@2 and core-js@3. Core-js@2 includes all stable JS features while core-js@3 includes most recent ones like Array.prototype.flatMap methods from ECMAScript 2018. You can see the JS properties that each Babel core-js version is supporting in this compatibility table. To specify which core-jsoption you want to use, pass it in @babel/preset-env as the core-js option. The default version used is core-js@2, but if you do not specify one in your config, webpack will throw a warning.

babel.config.js

There are different ways to configure babel based on your project needs ( read more about it here). You could use either .babelrc, .baberc.js or babel.config.js or simply configure it straight in the babel-loader options in your build script. The recommended way is to have a projected wide configuration so that tools like tests setup with JEST can make use of it as well. babel.config.js was the right option for us because we needed to set the browserslist option programmatically so we can share it across all of our projects. This is the final @babel@preset-env config we share across projects.

@babel/preset-env shared config

Updating test configurations

After updating to babel 7, all the React tests were failing because of a dependency on Babel 6. The current jest 23.x that we were using was relying on babel-runtime@6.x which led to conflicts in our current setup. There was a possible workaround through babel-core@7.0.0-bridge.0 but that is no longer necessary starting with latest jest version, 24.0. Therefore we updated jest to latest version.

What actually gets in your bundle

You can set debug:true in @babel/preset-env config to actually see which polyfills are included for each file in your source code and for what reason (i.e. to support a certain browser in your browsers target options).

Babel debug:true build output

Also there are different solutions out there for analysing the bundle. This is a very good article describing a few of them. We used webpack-bundle-analyzer plugin and we could notice an addition of around 120kb in core-js polyfills after the update.

There is a difference of about 60kb between our current polyfills and what we used to have included by default with the babel 6 preset-env. Nevertheless this allows us to stop relying on tools like lodash and underscore to replace native ES6 feature like Object.assign and still be able to support a large range of browsers and devices.

Conclusion

Benefits of using Babel 7:

  • Ability to chose what to include in your bundle based on your targeted browsers and your source code with the useBuiltIn:’usage’ option in @babel/preset-env
  • Transparency on what gets included in your bundle and for what reason with the debug option in @babel/preset-env
  • greatly simplified choice of presets through the unification of all babel-preset-es201x into @babel/preset-env
  • On the fly polyfilling of new JS features like async-await according to your browsers target as soon as you start including them in your code.

What about you ? What babel configuration are you using and what other benefits do you find in upgrading to Babel 7 ?

Huge thanks to my colleagues Liam Tarpey and Sebastien Axinte for all their support throughout the research and implementation of this migration.

Thanks for reading! If you enjoyed this article, you are looking to progress in your tech career and you’ve got a love for learning languages (tech or otherwise), we’ve got lots of open roles in our Tech team!

--

--