What is babel-preset-env and why do I need it?
Tags: javascript, babel, webpack
Published: 2019-04-23 18:04:40

---
title: What is babel-preset-env and why do I need it?
published: true
description: What is babel-preset-env and why do I need it?
tags: javascript, babel, webpack
canonical_url: https://blog.jakoblind.no/babel-preset-env/
---


If you have followed any recent tutorial on how to set up a modern JavaScript project, you have installed Babel and then added _babel-preset-env_ to your _.babelrc_:







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







...and things works fine. It transpiles the ES6 for you just like you wanted to and you move on with the tutorial.







But what did you just do with your _.babelrc_ file and why does it work?







It's not a nice feeling to just type something that you read in a tutorial without really understand why you should use it. Let's look into what _babel-preset-env_ really do, and why you need it.







This is part 2 of my post about implementing ES6 with Babel and webpack. In [the first part](http://blog.jakoblind.no/babel-webpack-es6/), you learned the basics of what problems Babel solves.








Before I can tell you what babel-preset-env does, I need to explain the basics of Babel to you. It's good to refresh even if you feel you already know it.







## Babel from scratch







The most common way to use Babel is together with a build system such as webpack. When using Babel with a build tool it's easy to overlook how Babel really works. It feels like Babel and webpack is the same thing.







A good exercise is to learn Babel without a build system - even though you don't intend to use it that way in production. So get your editor and terminal ready and code along.







First create a new NPM project:







```
mkdir babel-test
cd babel-test
npm init -y
```







Next install Babel as dependency to your empty project:







```
npm install --save-dev @babel/core @babel/cli
```







Add a file called _input.js_ and add the following to it:







```javascript
const hello = () => console.log("hello world!");
```







That is an [arrow function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) which is an ES6 feature. This is supported in most browsers but [not](https://caniuse.com/#feat=arrow-functions) all, that's why it's a good idea to transpile it to ES5. Now let's run this file through Babel:







```
npx babel input.js --out-file output.js
```







If you open _output.js_, you'll see that nothing has changed. It's exactly the same content as _input.js_. That's not what you expected, was it? The reason for this is that Babel doesn't do anything out-of-the-box but Babel is built on presets and plugins. If you don't add any presets or plugins, then Babel will do nothing.







<blockquote>Babel doesn't do anything out-of-the-box
</blockquote>







### It's the Babel plugins that does the work







To make Babel actually _do_ something, we need to add a plugin. It's the plugins that does the heavy lifting.







Each plugin is it's own NPM library. So for every plugin you want to install, you have to install a new NPM library or you can use a preset that we'll come back to in the next section.







In the code you have written in _input.js_ you only have one ES6 feature: an arrow function. So what we are going to now is to install a Babel plugin that transpiles ES6 arrow functions.







Let's start by installing a plugin that transpiles the function you have written in _input.js_ file.







```
npm install --save-dev @babel/plugin-transform-arrow-functions
```







Next, you need to tell Babel to use the dependency. Add a file called _.babelrc_ file to the root of your project. This is the configuration file for Babel, and you'll use it to tell babel to use the plugin [@babel/plugin-transform-arrow-functions](https://babeljs.io/docs/en/babel-plugin-transform-arrow-functions) when doing the transpliation. This plugin only transpiles ES6 arrow functions.







```
{
  plugins: ['@babel/plugin-transform-arrow-functions']
}
```







Ok, that's it. Now you can re-run babel and look at the generated output.js file. It now contains the transpiled code!







```javascript
const hello = function () {
  return console.log("hello world!");
};
```







That's awesome! But if you want to use more ES6 features you would need to install one NPM package and add an entry in _.babelrc_ for _every_ feature. That's just too much work. But there is a solution to this: presets!







### Babel presets bundles together common Babel plugins







The Babel foundation has created presets that contains common bundles of plugins. That means you only have to do the NPM installation and babel configuration once and then a bunch of plugins are automatically installed for you.







There are many different Babel presets, both official presets from Babel foundation and unofficial presets from other organizations such as [Airbnb](https://github.com/airbnb/babel-preset-airbnb). Heck, you could even create your own preset if you want.







The official presets are:



  * @babel/preset-env
  * @babel/preset-flow
  * @babel/preset-react
  * @babel/preset-typescript






Every preset is its own NPM dependency that you need to install and configure. Ok, now you are _finally_ ready to learn about babel-preset-env.







## Ok, now babel-preset-env







Let's convert you mini-code base to use babel-preset-env instead of @babel/plugin-transform-arrow-functions







Install the NPM dependency:







```
npm install --save-dev @babel/preset-env
```







Next, configure in the preset section of your _.babelrc_ file







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







What you have done now, is that you have installed the basic configuration of babel-preset-env. Out-of-the-box you get all plugins you need to transpile all ES6 features!







But babel preset env is smarter than this. You can have even more fine grained controll over what plugins should be installed







## The unique selling point with babel-preset-env is that you can define what browsers you support







By default, babel-preset-env just installs _all_ ES6 plugin you'll need. But this can bloat up your bundle. Look at this example how modern ES6 is transpiled to old legacy JavaScript code





![](https://d4jyn86spyrm8.cloudfront.net/unnamed.jpg)From [this tweet](https://twitter.com/jamiebuilds/status/1022568923726639104) by [@jamiebuilds﻿](https://twitter.com/jamiebuilds/)





On the left is the ES6 code, then you can see in the middle how much code is generated if you must support very old browsers. And the amount of code needed to support not-super-old browsers to the right.







The amount of code needed to support old legacy browsers in this example is extreme.







So if you only use the default babel-preset-env you might end up in a bloated bundle. What can we do about this?







It would be nice if there were a way to tell Babel to not use _all_ plugins, but only a subset of plugins that you _really_ need. That way less of your code gets transpiled to bloated ES5 code.







If you read my [previous](http://blog.jakoblind.no/babel-webpack-es6/) post on this subject, you learned that most modern browsers already support most ES6 features. If you look at Google analytics for your site you might realize that 99% are on modern browsers. So maybe you don't have to support _all_ old browsers that have ever existed.







When you have made a decision on what browsers you want to support, you can tell babel exactly what browsers you should support with babel-preset-env. You do that with the config file called _.browserlistrc_ which is part of a [standard](https://github.com/browserslist/browserslist) that defines what browsers your app supports. Babel-preset-env reads from this config file.







You can, for example, say you don't support IE by adding the following to your _.browserlistrc_ file:







```
not ie all
```







or that you define that you only support browsers with a market share of 0.25% or more:







```
>0.25%
```







If you describe to babel-preset-env what browsers you support, it can use less plugins, and that means less unneeded code.







## How should my browserconfig look like?







Read your Google Analytics stats (or whatever tool you are using) to get an impression of what browsers your users are using, then use the [browerlist](https://github.com/browserslist/browserslist)[ docs](https://github.com/browserslist/browserslist) to compose your configuration.







If you don't use Google Analytics then a good default can be to support all browsers with a market share of 0.25% or higher like this:







```
>0.25%
```







Using "last 2 versions" is [not](https://jamie.build/last-2-versions) recommended.







You can get a list of all browsers supported by your browserlist config by running following command







```
npx browserslist
```







It will list all browsers in the console.







## Next step is to learn how to configure webpack







As I mentioned earlier, the most common way to use Babel is with webpack. So now that you know how babel works, a natural next step is to start looking into webpack.







I have created an email course that gives you one email per day that will only take a few minutes to read. After five days you have learned how to build a complete production ready webpack app. Get access today by [signing up](https://pages.convertkit.com/8eeb9f21b0/26777fab4c). It's free!


→→<a href="https://pages.convertkit.com/8eeb9f21b0/26777fab4c">Free webpack email course</a> ←←