Sitemap
codeburst

Bursts of code to power through your day. Web Development articles, tutorials, and news.

Babel & preset-env

📚 Compile to environments, not specifications

--

📑 Table of Contents

Babel is a compiler for JavaScript which allows using new language features (like async or arrow functions => ) without waiting for browser or runtime support. Here we’ll discuss JS specifications, runtime specification support and how to configure Babel for your code’s runtime.

Press enter or click to view image in full size
Babel in server and browser envs

ECMAScript (ES) Specifications

The ECMA Standards Orgs define the spec for JavaScript (ECMAScript or ES) amongst other things. In 2015 they made a commitment to release updates to the ES spec annually, with the release year included in the official name (es2015), eschewing the original spec edition-based naming scheme (es5).

These names can be used interchangeably:

  • es5 — old convention
  • es6 = es2015 (new convention)
  • es7 = es2016 etc

I prefer the es<edition num> as it’s short and timeless (a year will inevitably be skipped 😜). JS tooling, such as Babel, correctly use the official naming convention, hence why you’ll see es2015 , es2016 etc. Naming things is hard, apparently even specs with clear enumeration. Welcome to the fray.

How Babel Works

Babel analyses your JS code structure (as an Abstract Syntax Tree or AST) to find specific constructs, and applies a transformation to those tree nodes resulting in syntax executable by older JS runtimes.

Babel Plugins and Presets

In Babel, each AST transformation is packaged as a Babel plugin for simple sharing and composition. Babel presets are combinations of plugins to support particular environments. Initially, the recommended presets were plugin combinations to allow compatibility with ES spec versions. It’s important to note, the spec in the preset’s name is not the target version, but the source version. For example, babel-preset-es2015 would compile ES6(es2015) to ES5 and babel-preset-es2016 would compile ES7(es2016) to ES6(es2015). It wasn’t long before a preset covering all spec presets was introduced, preset-latest, simplifying the Babel configuration.

Browsers, Runtimes and the ES Spec

Unfortunately, browser and server runtimes do not align in their ES spec feature support. For example (using data from compat-table):

NodeJS v6.11.1 supports:

  • 97% of the ES6 spec feature list
  • 29% of the ES7 spec feature list etc

IE11 supports:

  • 99% of the ES5 spec feature list
  • 11% of the ES6 spec feature list
  • 3% of the ES7 spec feature list

This means some new language features might not get compiled for your environment if the wrong spec target is used. Compiling for the lowest spec version (ES5) is an option, but ideally you should only compile what is needed and ship as much native code as possible.

Thus, you should not rely on a spec version for defining your compilation output.

Fortunately, the Babel devs created a tool that can do the heavy lifting.

Enter preset-env

Babel preset-env is a preset that compiles down to a minimum of ES5 (preset-es2015), but can also take a browser or runtime version and determine which plugins are needed for that specific environment!

This avoids the problem of targeting a spec! It also avoids unnecessarily compiling code that does not need to be. Ultimately, Babel does less and you can ship your native code to your users where possible! This also replaces preset-latest as the recommended preset by the Babel folks.

How does preset-env work?!

preset-env uses the data from compat-table (a runtime/ECMAScript compatibility table) to determine which features need to be transformed to run within particular browser or runtime versions.

Get James Hegedus’s stories in your inbox

Join Medium for free to get updates from this writer.

Thanks to the creator(s), maintainers and contributors of Babel, preset-env and compat-table, your work is very much appreciated!

Using preset-env

Babel’s v7 Beta is close to release and merges preset-env and the CLI into the monorepo. To add these packages to your project run:

yarn add @babel/preset-env @babel/cli -D

Compile for Everything (that supports ES5)!

{
"presets": ["@babel/preset-env"]
}

Ideally, you want to compile as little code as possible, so try targeting the minimum environment for your code.

Compile for the Browser

{
"presets": [
["@babel/preset-env", {
"targets": {
"browsers": ["last 2 versions", "safari >= 7"]
}
}]
]
}

Browser List is the library Babel uses allowing you to specify the browser versions you wish to target, for example "last 2 versions" etc. The docs explain all the options. There’s also a nice site to see which browsers and versions your definition targets:

Some example queries (global coverage % is at the bottom of the page):

Compile for the Runtime

For NodeJS v6.11.1 we simply put:

{
"presets": [
["@babel/preset-env", {
"targets": {
"node": "6.11.1"
}
}]
]
}

If you compile Babel using the same version of Node that your production environment does, then you can simply specify to use the current runtime version.

{
"presets": [
["@babel/preset-env", {
"targets": {
"node": "current"
}
}]
]
}

Polyfills

To apply polyfills using preset-env you can toggle the flag useBuiltIns like so:

{
"presets": [
["@babel/preset-env", {
"targets": {
"node": "current"
},
"useBuiltIns": true,
}]
]
}

This will apply non-experimental/stage-x polyfills as required. You do need to add yarn add @babel/polyfill and add import "@babel/polyfill" once to your project.

For more details checkout the Options section of the docs.

Conclusion

Compile to your user’s environments, not the spec. Use Babel preset-env with Browserlist and compat-table to define the environment you’re targeting (with the ES5 spec, as a worst case target). Use all the language features today and ... Profit?! 😄

For a deeper dive into the compiled outputs of Babel see my next post:

ES6+ in Cloud Functions for Firebase #2
Babel Boogaloo!

If you found this useful, please share with your friends & colleagues.

--

--

James Hegedus
James Hegedus

Written by James Hegedus

https://jthegedus.dev Prefer-er of the simple things. Go, HTMX, Tailwind, Google Cloud, Firebase, Cloudflare, self-hosting @jthegedus on all platforms.

codeburst
codeburst

Published in codeburst

Bursts of code to power through your day. Web Development articles, tutorials, and news.