This is how I build Babel plug-ins

Eytan Manor
Oct 8, 2018 · 7 min read

The idea of writing such article popped into my mind while working on my Webflow/React transpiler. All I wanted to do was to take a JS code string and transform it in such way that globals won’t be redefined if already so:

At the beginning I thought I could do that with some help from a regular expression; but boy was I wrong.

A regular expression is simply not enough because it ignores the concept of scoped variables completely and works on a string as if it was a plain text. To determine a global variable, what we need to ask ourselves is: Is this variable already declared in the current scope or one of its parent scopes?

The way to go with such question would be breaking down the code into nodes, where each node represents a part in our code and all the nodes are connected with each other in a relational manner. This whole node formation is called AST — abstract syntax tree, which can be used to easily lookup scopes and variables and other elements which are related to our code.

An example AST may look like so:

Image for post
Image for post

Example taken from Lachezar Nickolov’s article about JS ASTs.

Obviously, breaking down our code into nodes is not a walk in the park. Luckily, we have a tool called Babel which already does that.

Babel to the rescue

Babel is a project which originally started to transform the latest es20XX syntax into es5 syntax for better browser compatibility. As the Ecmascript committee keeps updating the standards of the Ecmascript language, plug-ins provide an excellent and maintainable solution to easily update the Babel compiler’s behavior.

Babel is made out of numerous components which work together to bring the latest Ecmascript syntax to life. Specifically the code transformation flow works with the following components and following relations:

Image for post
Image for post

Now you have a better understanding of Babel and you can actually understand what’s happening when you build a plug-in; and speaking of which, how do we do that?

Building and using a Babel plug-in

First of all I would like us to understand Babel’s generated AST as this is essential for building the plug-in, because the plug-in’s gonna manipulate the AST and therefore we need to understand it. If you’ll go to astexplorer.net you’ll find an amazing compiler that will transform code into AST. Let’s take the code foo = "foo" as an example. The generated AST should look like so:

Image for post
Image for post

As you can see, each node in the tree represents a part of the code, and it’s recursive. The assignment expression foo = "foo" uses the operator =, the operand on the left is an identifier named foo and the operand on the right is a literal with the value "foo". So that’s how it goes, each part of the code can be presented as a node which is made out of other nodes, each node has a type and additional properties based on its type.

Now let’s say that we would like to change the value "foo" to "bar", hypothetically speaking what we will have to do would be grab the corresponding literal node and change its value from "foo", to "bar". Let’s take this simple example and turn it into a plug-in.

I’ve prepared a quick template project that you can use to quickly write plug-ins and test them by transforming them. The project can be downloaded by cloning this repository. The project contains the following files:

To implement our plug-in, copy the following content and paste it in the in.js file:

foo = "foo"

and the following content to the transform.js file:

To initiate the transformation, simply run $ node transform.js. Now open the out.js file and you should see the following content:

foo = "bar"

The visitor property is where the actual manipulation of the AST should be done. It walks through the tree and runs the handlers for each specified node type. In our case, whenever the visitor has encountered a node of type AssignmentExpression node, it will replace the right operand with "bar" in case we assign the the "foo" value to foo. We can add a manipulation handler for any node type that we want, it can be AssignmentExpression, Identifier, Literal, or even Program, which is the root node of the AST.

So going back to the main purpose of for which we gathered, I’ll first provide you with a reminder:

We will first take all global assignments and turn it into member assignment expressions of window to prevent confusions and potential misunderstandings. I like to start by first exploring the desired AST output:

Image for post
Image for post

And then writing the plug-in itself accordingly:

I will now introduce you to 2 new concepts that I haven’t mention before but are being used in the plug-in above:

Now we will add the missing peace to the puzzle which is transforming assignment expressions into conditional assignment expressions. So we wanna turn this code:

window.foo = 'foo'

Into this code:

if (typeof window.foo === 'undefined') window.foo = 'foo'

If you’ll investigate that code’s AST you’ll see that we’re dealing with 3 new node types:

Notice how each node is composed out of the one above it. Accordingly, we will update our plug-in. We will keep the old logic, where we turn global variables into members of window, and on top of that, we will make it conditional with the IfStatement:

So basically what we do here is checking whether we deal with a window member assignment expression, and if so we will create the conditional statement and replace it with the current node. Few notes:

So there you go, by now the plug-in should be complete. It’s not the most complex plug-in out there but it’s definitely a good example for this intro that will give you a good basis for further plug-ins that you’ll build down the road.

As a recap, whenever you forget for any reason how a plug-in works, go through this article. As you work on the plug-in itself, investigate through the desired AST outcome at astexplorer.net and for API docs I recommend you to work with this wonderful handbook.

The Guild

The Guild

Thanks to Urigo

Eytan Manor

Written by

Eytan is a JavaScript artist who comes from the land of the Promise(). His hobbies are eating, sleeping; and open-source… He loves open-source.

The Guild

The Guild

The Guild

Eytan Manor

Written by

Eytan is a JavaScript artist who comes from the land of the Promise(). His hobbies are eating, sleeping; and open-source… He loves open-source.

The Guild

The Guild

The Guild

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store