Permalink
Switch branches/tags
Nothing to show
Find file Copy path
987 lines (729 sloc) 27.1 KB

Babel User Handbook

This document covers everything you ever wanted to know about using Babel and related tooling.

cc-by-4.0

This handbook is available in other languages, see the README for a complete list.

Table of Contents

Introduction

Babel is a generic multi-purpose compiler for JavaScript. Using Babel you can use (and create) the next generation of JavaScript, as well as the next generation of JavaScript tooling.

JavaScript as a language is constantly evolving, with new specs and proposals coming out with new features all the time. Using Babel will allow you to use many of these features years before they are available everywhere.

Babel does this by compiling down JavaScript code written with the latest standards into a version that will work everywhere today. This process is known as source-to-source compiling, also known as transpiling.

For example, Babel could transform the new ES2015 arrow function syntax from this:

const square = n => n * n;

Into the following:

const square = function square(n) {
  return n * n;
};

However, Babel can do much more than this as Babel has support for syntax extensions such as the JSX syntax for React and Flow syntax support for static type checking.

Further than that, everything in Babel is simply a plugin and anyone can go out and create their own plugins using the full power of Babel to do whatever they want.

Even further than that, Babel is broken down into a number of core modules that anyone can use to build the next generation of JavaScript tooling.

Many people do too, the ecosystem that has sprung up around Babel is massive and very diverse. Throughout this handbook I'll be covering both how built-in Babel tools work as well as some useful things from around the community.

For future updates, follow @thejameskyle on Twitter.


Setting up Babel

Since the JavaScript community has no single build tool, framework, platform, etc., Babel has official integrations for all of the major tooling. Everything from Gulp to Browserify, from Ember to Meteor, no matter what your setup looks like there is probably an official integration.

For the purposes of this handbook, we're just going to cover the built-in ways of setting up Babel, but you can also visit the interactive setup page for all of the integrations.

Note: This guide is going to refer to command line tools like node and npm. Before continuing any further you should be comfortable with these tools.

babel-cli

Babel's CLI is a simple way to compile files with Babel from the command line.

Let's first install it globally to learn the basics.

$ npm install --global babel-cli

We can compile our first file like so:

$ babel my-file.js

This will dump the compiled output directly into your terminal. To write it to a file we'll specify an --out-file or -o.

$ babel example.js --out-file compiled.js
# or
$ babel example.js -o compiled.js

If we want to compile a whole directory into a new directory we can do so using --out-dir or -d.

$ babel src --out-dir lib
# or
$ babel src -d lib

Running Babel CLI from within a project

While you can install Babel CLI globally on your machine, it's much better to install it locally project by project.

There are two primary reasons for this.

  1. Different projects on the same machine can depend on different versions of Babel allowing you to update one at a time.
  2. It means you do not have an implicit dependency on the environment you are working in. Making your project far more portable and easier to setup.

We can install Babel CLI locally by running:

$ npm install --save-dev babel-cli

Note: Since it's generally a bad idea to run Babel globally you may want to uninstall the global copy by running:

$ npm uninstall --global babel-cli

After that finishes installing, your package.json file should look like this:

{
  "name": "my-project",
  "version": "1.0.0",
  "devDependencies": {
    "babel-cli": "^6.0.0"
  }
}

Now instead of running Babel directly from the command line we're going to put our commands in npm scripts which will use our local version.

Simply add a "scripts" field to your package.json and put the babel command inside there as build.

  {
    "name": "my-project",
    "version": "1.0.0",
+   "scripts": {
+     "build": "babel src -d lib"
+   },
    "devDependencies": {
      "babel-cli": "^6.0.0"
    }
  }

Now from our terminal we can run:

npm run build

This will run Babel the same way as before, only now we are using a local copy.

babel-register

The next most common method of running Babel is through babel-register. This option will allow you to run Babel just by requiring files, which may integrate with your setup better.

Note that this is not meant for production use. It's considered bad practice to deploy code that gets compiled this way. It is far better to compile ahead of time before deploying. However this works quite well for build scripts or other things that you run locally.

First let's create an index.js file in our project.

console.log("Hello world!");

If we were to run this with node index.js this wouldn't be compiled with Babel. So instead of doing that, we'll setup babel-register.

First install babel-register.

$ npm install --save-dev babel-register

Next, create a register.js file in the project and write the following code:

require("babel-register");
require("./index.js");

What this does is registers Babel in Node's module system and begins compiling every file that is require'd.

Now, instead of running node index.js we can use register.js instead.

$ node register.js

Note: You can't register Babel in the same file that you want to compile. As node is executing the file before Babel has a chance to compile it.

require("babel-register");
// not compiled:
console.log("Hello world!");

babel-node

If you are just running some code via the node CLI the easiest way to integrate Babel might be to use the babel-node CLI which largely is just a drop in replacement for the node CLI.

Note that this is not meant for production use. It's considered bad practice to deploy code that gets compiled this way. It is far better to compile ahead of time before deploying. However this works quite well for build scripts or other things that you run locally.

First make sure that you have babel-cli installed.

$ npm install --save-dev babel-cli

Note: If you are wondering why we are installing this locally, please read the Running Babel CLI from within a project section above.

Then replace wherever you are running node with babel-node.

If you are using npm scripts you can simply do:

  {
    "scripts": {
-     "script-name": "node script.js"
+     "script-name": "babel-node script.js"
    }
  }

Otherwise you'll need to write out the path to babel-node itself.

- node script.js
+ ./node_modules/.bin/babel-node script.js

Tip: You can also use npm-run.

babel-core

If you need to use Babel programmatically for some reason, you can use the babel-core package itself.

First install babel-core.

$ npm install babel-core
var babel = require("babel-core");

If you have a string of JavaScript you can compile it directly using babel.transform.

babel.transform("code();", options);
// => { code, map, ast }

If you are working with files you can use either the asynchronous api:

babel.transformFile("filename.js", options, function(err, result) {
  result; // => { code, map, ast }
});

Or the synchronous api:

babel.transformFileSync("filename.js", options);
// => { code, map, ast }

If you already have a Babel AST for whatever reason you may transform from the AST directly.

babel.transformFromAst(ast, code, options);
// => { code, map, ast }

For all of the above methods, options refers to https://babeljs.io/docs/usage/api/#options.


Configuring Babel

You may have noticed by now that running Babel on its own doesn't seem to do anything other than copy JavaScript files from one location to another.

This is because we haven't told Babel to do anything yet.

Since Babel is a general purpose compiler that gets used in a myriad of different ways, it doesn't do anything by default. You have to explicitly tell Babel what it should be doing.

You can give Babel instructions on what to do by installing plugins or presets (groups of plugins).

.babelrc

Before we start telling Babel what to do. We need to create a configuration file. All you need to do is create a .babelrc file at the root of your project. Start off with it like this:

{
  "presets": [],
  "plugins": []
}

This file is how you configure Babel to do what you want.

Note: While you can also pass options to Babel in other ways the .babelrc file is convention and is the best way.

babel-preset-es2015

Let's start by telling Babel to compile ES2015 (the newest version of the JavaScript standard, also known as ES6) to ES5 (the version available in most JavaScript environments today).

We'll do this by installing the "es2015" Babel preset:

$ npm install --save-dev babel-preset-es2015

Next we'll modify our .babelrc to include that preset.

  {
    "presets": [
+     "es2015"
    ],
    "plugins": []
  }

babel-preset-react

Setting up React is just as easy. Just install the preset:

$ npm install --save-dev babel-preset-react

Then add the preset to your .babelrc file:

  {
    "presets": [
      "es2015",
+     "react"
    ],
    "plugins": []
  }

babel-preset-stage-x

JavaScript also has some proposals that are making their way into the standard through the TC39's (the technical committee behind the ECMAScript standard) process.

This process is broken through a 5 stage (0-4) process. As proposals gain more traction and are more likely to be accepted into the standard they proceed through the various stages, finally being accepted into the standard at stage 4.

These are bundled in babel as 4 different presets:

  • babel-preset-stage-0
  • babel-preset-stage-1
  • babel-preset-stage-2
  • babel-preset-stage-3

Note that there is no stage-4 preset as it is simply the es2015 preset above.

Each of these presets requires the preset for the later stages. i.e. babel-preset-stage-1 requires babel-preset-stage-2 which requires babel-preset-stage-3.

Simply install the stage you are interested in using:

$ npm install --save-dev babel-preset-stage-2

Then you can add it to your .babelrc config.

  {
    "presets": [
      "es2015",
      "react",
+     "stage-2"
    ],
    "plugins": []
  }

Executing Babel-generated code

So you've compiled your code with Babel, but this is not the end of the story.

babel-polyfill

Almost all futuristic JavaScript syntax can be compiled with Babel, but the same is not true for APIs.

For example, the following code has an arrow function that needs to be compiled:

function addAll() {
  return Array.from(arguments).reduce((a, b) => a + b);
}

Which turns into this:

function addAll() {
  return Array.from(arguments).reduce(function(a, b) {
    return a + b;
  });
}

However, this still won't work everywhere because Array.from doesn't exist in every JavaScript environment.

Uncaught TypeError: Array.from is not a function

To solve this problem we use something called a Polyfill. Simply put, a polyfill is a piece of code that replicates a native api that does not exist in the current runtime. Allowing you to use APIs such as Array.from before they are available.

Babel uses the excellent core-js as its polyfill, along with a customized regenerator runtime for getting generators and async functions working.

To include the Babel polyfill, first install it with npm:

$ npm install --save babel-polyfill

Then simply include the polyfill at the top of any file that requires it:

import "babel-polyfill";

babel-runtime

In order to implement details of ECMAScript specs, Babel will use "helper" methods in order to keep the generated code clean.

Since these helpers can get pretty long, and they get added to the top of every file you can move them into a single "runtime" which gets required.

Start by installing babel-plugin-transform-runtime and babel-runtime:

$ npm install --save-dev babel-plugin-transform-runtime
$ npm install --save babel-runtime

Then update your .babelrc:

  {
    "plugins": [
+     "transform-runtime",
      "transform-es2015-classes"
    ]
  }

Now Babel will compile code like the following:

class Foo {
  method() {}
}

Into this:

import _classCallCheck from "babel-runtime/helpers/classCallCheck";
import _createClass from "babel-runtime/helpers/createClass";

let Foo = function () {
  function Foo() {
    _classCallCheck(this, Foo);
  }

  _createClass(Foo, [{
    key: "method",
    value: function method() {}
  }]);

  return Foo;
}();

Rather than putting the _classCallCheck and _createClass helpers in every single file where they are needed.


Configuring Babel (Advanced)

Most people can get by using Babel with just the built-in presets, but Babel exposes much finer-grained power than that.

Manually specifying plugins

Babel presets are simply collections of pre-configured plugins, if you want to do something differently you manually specify plugins. This works almost exactly the same way as presets.

First install a plugin:

$ npm install --save-dev babel-plugin-transform-es2015-classes

Then add the plugins field to your .babelrc.

  {
+   "plugins": [
+     "transform-es2015-classes"
+   ]
  }

This gives you much finer grained control over the exact transforms you are running.

For a full list of official plugins see the Babel Plugins page.

Also take a look at all the plugins that have been built by the community. If you would like to learn how to write your own plugin read the Babel Plugin Handbook.

Plugin options

Many plugins also have options to configure them to behave differently. For example, many transforms have a "loose" mode which drops some spec behavior in favor of simpler and more performant generated code.

To add options to a plugin, simply make the following change:

  {
    "plugins": [
-     "transform-es2015-classes"
+     ["transform-es2015-classes", { "loose": true }]
    ]
  }

I'll be working on updates to the plugin documentation to detail every option in the coming weeks. Follow me for updates.

Customizing Babel based on environment

Babel plugins solve many different tasks. Many of them are development tools that can help you debugging your code or integrate with tools. There are also a lot of plugins that are meant for optimizing your code in production.

For this reason, it is common to want Babel configuration based on the environment. You can do this easily with your .babelrc file.

  {
    "presets": ["es2015"],
    "plugins": [],
+   "env": {
+     "development": {
+       "plugins": [...]
+     },
+     "production": {
+       "plugins": [...]
+     }
    }
  }

Babel will enable configuration inside of env based on the current environment.

The current environment will use process.env.BABEL_ENV. When BABEL_ENV is not available, it will fallback to NODE_ENV, and if that is not available it will default to "development".

Unix

$ BABEL_ENV=production [COMMAND]
$ NODE_ENV=production [COMMAND]

Windows

$ SET BABEL_ENV=production
$ [COMMAND]

Note: [COMMAND] is whatever you use to run Babel (ie. babel, babel-node, or maybe just node if you are using the register hook).

Tip: If you want your command to work across unix and windows platforms then use cross-env.

Making your own preset

Manually specifying plugins? Plugin options? Environment-based settings? All this configuration might seem like a ton of repetition for all of your projects.

For this reason, we encourage the community to create their own presets. This could be a preset for the specific node version you are running, or maybe a preset for your entire company.

It's easy to create a preset. Say you have this .babelrc file:

{
  "presets": [
    "es2015",
    "react"
  ],
  "plugins": [
    "transform-flow-strip-types"
  ]
}

All you need to do is create a new project following the naming convention babel-preset-* (please be responsible with this namespace), and create two files.

First, create a new package.json file with the necessary dependencies for your preset.

{
  "name": "babel-preset-my-awesome-preset",
  "version": "1.0.0",
  "author": "James Kyle <me@thejameskyle.com>",
  "dependencies": {
    "babel-preset-es2015": "^6.3.13",
    "babel-preset-react": "^6.3.13",
    "babel-plugin-transform-flow-strip-types": "^6.3.15"
  }
}

Then create an index.js file that exports the contents of your .babelrc file, replacing plugin/preset strings with require calls.

module.exports = {
  presets: [
    require("babel-preset-es2015"),
    require("babel-preset-react")
  ],
  plugins: [
    require("babel-plugin-transform-flow-strip-types")
  ]
};

Then simply publish this to npm and you can use it like you would any preset.


Babel and other tools

Babel is pretty straight forward to setup once you get the hang of it, but it can be rather difficult navigating how to set it up with other tools. However, we try to work closely with other projects in order to make the experience as easy as possible.

Static analysis tools

Newer standards bring a lot of new syntax to the language and static analysis tools are just starting to take advantage of it.

Linting

One of the most popular tools for linting is ESLint, because of this we maintain an official babel-eslint integration.

First install eslint and babel-eslint.

$ npm install --save-dev eslint babel-eslint

Next create or use the existing .eslintrc file in your project and set the parser as babel-eslint.

  {
+   "parser": "babel-eslint",
    "rules": {
      ...
    }
  }

Now add a lint task to your npm package.json scripts:

  {
    "name": "my-module",
    "scripts": {
+     "lint": "eslint my-files.js"
    },
    "devDependencies": {
      "babel-eslint": "...",
      "eslint": "..."
    }
  }

Then just run the task and you will be all setup.

$ npm run lint

For more information consult the babel-eslint or eslint documentation.

Code Style

JSCS has merged with ESLint, so checkout Code Styling with ESLint.

JSCS is an extremely popular tool for taking linting a step further into checking the style of the code itself. A core maintainer of both the Babel and JSCS projects (@hzoo) maintains an official integration with JSCS.

Even better, this integration now lives within JSCS itself under the --esnext option. So integrating Babel is as easy as:

$ jscs . --esnext

From the cli, or adding the esnext option to your .jscsrc file.

  {
    "preset": "airbnb",
+   "esnext": true
  }

For more information consult the babel-jscs or jscs documentation.

Documentation

Using Babel, ES2015, and Flow you can infer a lot about your code. Using documentation.js you can generate detailed API documentation very easily.

Documentation.js uses Babel behind the scenes to support all of the latest syntax including Flow annotations in order to declare the types in your code.

Frameworks

All of the major JavaScript frameworks are now focused on aligning their APIs around the future of the language. Because of this, there has been a lot of work going into the tooling.

Frameworks have the opportunity not just to use Babel but to extend it in ways that improve their users' experience.

React

React has dramatically changed their API to align with ES2015 classes (Read about the updated API here). Even further, React relies on Babel to compile it's JSX syntax, deprecating it's own custom tooling in favor of Babel. You can start by setting up the babel-preset-react package following the instructions above.

The React community took Babel and ran with it. There are now a number of transforms built by the community.

Most notably the babel-plugin-react-transform plugin which combined with a number of React-specific transforms can enable things like hot module reloading and other debugging utilities.

Text Editors and IDEs

Introducing ES2015, JSX, and Flow syntax with Babel can be helpful, but if your text editor doesn't support it then it can be a really bad experience. For this reason you will want to setup your text editor or IDE with a Babel plugin.


Babel Support

Babel has a very large and quickly growing community, as we grow we want to ensure that people have all the resources they need to be successful. So we provide a number of different channels for getting support.

Remember that across all of these communities we enforce a Code of Conduct. If you break the Code of Conduct, action will be taken. So please read it and be conscious of it when interacting with others.

We are also looking to grow a self-supporting community, for people who stick around and support others. If you find someone asking a question you know the answer to, take a few minutes and help them out. Try your best to be kind and understanding when doing so.

Babel Forum

Discourse has provided us with a hosted version of their forum software for free (and we love them for it!). If forums are your thing please stop by discuss.babeljs.io.

Babel Chat

Everyone loves Slack. If you're looking for immediate support from the community then come chat with us at slack.babeljs.io.

Babel Issues

Babel uses the issue tracker provided by Github.

You can see all the open and closed issues on Github.

If you want to open a new issue:

Creating an awesome Babel bug report

Babel issues can sometimes be very difficult to debug remotely, so we need all the help we can get. Spending a few more minutes crafting a really nice bug report can help get your problem solved significantly faster.

First, try isolating your problem. It's extremely unlikely that every part of your setup is contributing to the problem. If your problem is a piece of input code, try deleting as much code as possible that still causes an issue.

[WIP]


For future updates, follow @thejameskyle on Twitter.