Babel under the hood.

Have you ever thought how this awesome tool which you use in your daily life works under the hood? How does compilers you use in our daily life work? Do you need your own customized compilation? You should find this article beneficial then.

Babel is an excellent tool. It’s used at Facebook, Google, Netflix, and hundreds of other companies. It’s downloaded more than 7 million times a month on npm. It not only provides us to use ES6 but also it provides polyfills, ES7, JSX and flow support. If these are not enough, Babel aligns closely with TC39 (the technical committee that leads the design and development of JavaScript) and provides implementation of new JavaScript features which are just proposals not even finalized by the TC39 community. How awesome is that!!

Ok without further ado, lets jump straight on how Babel works.
Babel is a source to source compiler. For understanding Babel, let’s consider the most loved feature of ES6 : the arrow function!!
Suppose, you want this arrow function Javascript code:

(foo, bar) => foo + bar;

to be compiled into, browser supported JavaScript code:

"use strict";
(function (foo, bar) {
return foo + bar;
});

This involves three primary stages:

Stage 1: Parsing

Babel takes the source code and parses it into a abstract representation of the code. This abstract representation is called AST ( Abstract Syntax Tree).

An AST is a tree representation of the abstract syntactic structure of source code. Each node of the tree denotes a construct occurring in the source code. They are basically used for easy transformation of source code.

This is taken care by the Babel’s babylon parser.
The AST representation of our arrow function(foo, bar) => foo + bar; will be:

// AST shortened for clarity
{
"program": {
"body": [
{
"type": "ExpressionStatement",
"expression": {
"type": "ArrowFunctionExpression",
"params": [
{
"type": "Identifier",
"name": "foo"
},
{
"type": "Identifier",
"name": "bar"
}
],
"body": {
"type": "BinaryExpression",
"left": {
"type": "Identifier",
"name": "foo"
},
"operator": "+",
"right": {
"type": "Identifier",
"name": "bar"
}
}
}
}
]
}
}

As you can see, the given AST is describing each part of the syntax of the source code and their relation to each other. Consider playing with different ASTs of different source codes from this site to understand AST better.

Stage 2 : Transformation

This is where the magic occurs. In this stage, Babel takes the AST from the last step and manipulates it accordingly such that the resultant AST represents a browser suppported code.

This stage is taken care by a Babel plugin/preset. Presets are just simply an array of plugins that make it easier to run a whole a set of transforms without specifying each one manually. You could use Babel’s plugin/preset or write your own plugin/preset for your own customised compilation.

These plugins use babel-traverse to traverse through the AST and contains the code which defines how to modify/replace the original AST with the new AST.

The arrow function’s AST generated in the last step is manipulated to a new AST by traversing through the AST using babel-traverse and replacing the nodes of the AST (this replacement is done by the Babel plugin code).

This new AST represents browser supported code for arrow function:

// AST shortened for clarity
{
"program": {
"type": "Program",
"body": [
{
"type": "ExpressionStatement",
"expression": {
"type": "Literal",
"value": "use strict"
}
},
{
"type": "ExpressionStatement",
"expression": {
"type": "FunctionExpression",
"async": false,
"params": [
{
"type": "Identifier",
"name": "foo"
},
{
"type": "Identifier",
"name": "bar"
}
],
"body": {
"type": "BlockStatement",
"body": [
{
"type": "ReturnStatement",
"argument": {
"type": "BinaryExpression",
"left": {
"type": "Identifier",
"name": "foo"
},
"operator": "+",
"right": {
"type": "Identifier",
"name": "bar"
}
}
}
]
},
"parenthesizedExpression": true
}
}
]
}
}

Take a look at Babel’s arrow function plugin code and read this excellent babel plugin handbook to understand how to modify the AST accordingly or create you own Babel plugin for your own customised compilation.

Stage 3 : Code Generation

In this stage, the transformed new AST in the previous step is turned into its source code (browser supported). Yay!!

"use strict";
(function (foo, bar) {
return foo + bar;
});

This is taken care by the Babel’s babel-generator.

So, the whole flow of the compilation can be summed up like this:

Babel work flow

Conclusion:
So that’s how Babel works under the hood. If you want to dive deep into Babel you can refer the docs here. Babel has recently started accepting donations, you can show your gratitude by donating to Babel. Or you can contribute ( like me) to Babel to build your skills and resume.

Thanks for reading.
If you enjoyed this article, please hit the recommend button.