Migrate your app to Babel 7 — A case study
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-0
—stage-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-0
—stage-3
have been deprecated (more about this here) and split into twocore-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 thetargets
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-js
option 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.
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).
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!