Babel Polyfills, Transforms & Presets
Babel is really an amazing accomplishment by an open source community and an example of another kind of declarative, plugin-driven piece of software, like Webpack that pushes Javascript forward.
You may start from where we left off or clone the git repo and checkout this branch like so.
git clone git@github.com:lawwantsin/webpack-course.git
cd webpack-course
git checkout babel2
npm install
Let’s get a bit more into how Babel works, by adding polyfills to our codebase to extend the browser’s current capabilities and run features that still being debated in the standards committee. Really cool way to evolve a language.
Now let’s add something that’s definitely going to be in the language. In our
main.js
.
var a = async () => {
await console.log("Hello from the future!")
}
And in .babelrc
we add the plugin.
{
"plugins": ["transform-es2015-arrow-functions", "async-to-promises"]
}
This should add code to build a promise in the ES5 syntax. When we run npm install babel-plugin-async-to-promises
in our terminal we see.
And we see, if we run this, the promise code is added and called.
babel src/main.js
Async/Await functions are working their way into many evergreen browsers, but at this point, it's still a part of the ES2017 spec. Either way, in IE 11, we'll need to include a polyfill to run even the transpiled code.
So in the terminal, let's install a new package:
npm install babel-polyfill
In webpack.dev.js
add babel-polyfill
to the front of main.js.
main: ["babel-polyfill", "./src/main.js"]
Run npm start
. We can see main-bundle.js
is quite a bit bigger now. Adding
babel-polyfill
to that array tacked the whole module to the front of our
main.js
code.
To reduce this and any polyfill, it's really best to use the exact fill you'll need. Change the main entry again and rerun the server.
main: ["core-js/fn/promise", "./src/main.js"]
The difference is clear. While polyfills will only be run if they're not already implemented natively in the user's browser, they'll still be shipped in the bundle.
Let's restore main to it's former self.
main: "./src/main.js"
Babel Presets
We can add features one at a time with plugins, or we can use presets to include
all the features of a particular year or a particular way of working. There’s a
preset for react development which compiles JSX for you. Presets make setup
easier. And env
is the current preset that works best in most situations.
So let’s wrap up our overview of Babel and setup a full ES2017 feature stack, so we can finally start coding our project the modern way. In your terminal:
npm install babel-preset-env
In .babelrc
, just this:
{
"presets": [
[
"env",
{
"debug": true
}
]
]
}
When we rerun the devServer, we see debugging information
If we change the target, we'll see a different output of polyfills and
transforms based on what that browser needs. Babel uses
The Compat-table to determine the
current state of browser features. So if we add a target to our .babelrc
:
{
"presets": [
[
"env",
{
"targets": {
"browsers": ["last 2 versions"]
},
"debug": true
}
]
],
"plugins": ["transform-runtime"]
}
Your main.js
should look like this:
require("babel-runtime/regenerator")
require("./main.css")
require("./images/link.jpg")
require("./index.html")
var a = async args => {
const { a, b } = args
await console.log("Hello from the future!", a, b)
}
a({ a: 1, b: 2 })
Finally add the package and rerun:
npm install babel-plugin-transform-runtime
npm run start
We see a list of the supported browsers and the plugins needed to target them. No surprise that IE 10 and Android 4.4.3 are causing the extra transforms and the total bundle size has increased. Interestingly, if you change the target to the lastest 1 version, it's IE 11 and Android 56 and the bundle size is the same.
Challenge
Feel free to add a mystery Javascript feature yourself or specific target
browser as outlined here and
practice looking at the output with babel src/main.js
, see if it’s what you’d
expect.
In Sum
Transpilers a fascinating part of the javascript evolution and allows for lots of experimentation with the look and feel of a new syntax, before the makers of the engines commit to implementation.
This is the final code:
git checkout babel2-final
Next Up
In the next article we’ll ditch the webpack dev server to serve our files from a server we’ll build using express and some clever middleware. We’ll customize our output and get setup for a real full stack node app.