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
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 yarn add babel-plugin-async-to-promises
in our terminal we see.
And we see, if we run this, the promise code is added and called.
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.
yarn add babel-polyfill
In webpack.dev.js
add babel-polyfill to the front of main.js.
main: ["babel-polyfill", "./src/main.js"]
Run yarn start
. You can 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 shown in this image. While polyfills will only be used if they're not already implemented natively in the user's browser.
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.
yarn add 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:
yarn add babel-plugin-transform-runtime
yarn 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 yarn 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 engine commit to implementation.
This is the final code:
git checkout babel2-final
How much of your code can be represnted by integer? And can it recompile itself into assembler?