Wrote my first babel plugin!( Its Simple )
Sanket Maru
Posted on June 22, 2019
To write a babel plugin first you need to understand how babel plugins work. I will write down the things i required to write the plugin :-
- Go through the basics of Babel-handbook. Basics will help to understand what is an AST, parsing, traversal of AST (Stages of Babel).
- Play with Ast-explorer This will help to identify the different visitors of AST and which visitor you want to catch them to manipulate the paths.
- Setup a CRA (create-react-app) or a simple node project with a webpack config createapp.dev is useful to get things done fast.
- Debug, debug and debug........ Debug other plugins code. Setup vscode to debug the babel plugins inside node_modules. I will be covering a seperate blog on debbuging plugins and difficulties i faced developing a babel plugin Below is my vscode launch.json
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${workspaceFolder}/scripts/build.js"
}
Motivation
There are chances that some part of your code doesn't get executed on a mobile device and functionality is completely hidden from the user. The code still resides in the bundle and is downloaded by the user.
This babel plugin will remove the code developer has marked it as desktop and will never be included in the chunk.
How do you do it ? Its Simple..
visitor: {
Program(programPath) {
programPath.traverse({
ClassMethod(path) {
if (path.node.key.name.endsWith(classMethodEnv)) {
path.remove();
}
},
JSXElement(path) {
path.node.openingElement.attributes.forEach(ele => {
if (ele.name.name === jsxEnv)
path.remove();
});
}
});
}
}
We want to transform the AST such that every Class Method and JSXElement gets visited and removed if it matches the condition.
Babel: Visitors
I have made the plugin use a Program(path) visitor, and then do a path.traverse for all the visitors. This is done to explicitly process the whole file at the first chance plugin gets. If this is not done then it doesn't ensure ordering of plugins and your visitor might not get visited as it has been compiled to a different state by other plugins.
Other option you can make your plugin work is to use a Class visitor and traverse for the class methods from there.
Now that we are done with the plugin, we will be using it a react app to test it out.
Published as a npm library here
Usage
Your React Component
export default class App extends Component {
handleClick_mobile() {
console.log("Mobile Handle Click");
}
handleClick_desktop() {
console.log("Desktop handle Click");
}
render() {
return (
<div>
<table>
<tr data-mobile onClick={this.handleClick_mobile.bind(this)}>
<td>Mobile</td>
</tr>
<tr data-desktop onClick={this.handleClick_desktop.bind(this)}>
<td>Web</td>
</tr>
</table>
</div>
);
}
}
will be transpiled to :-
export default class App extends Component {
handleClick_mobile() {
console.log("Mobile Handle Click");
}
render() {
return (
<div>
<table>
<tr data-mobile onClick={this.handleClick_mobile.bind(this)}>
<td>Mobile</td>
</tr>
</table>
</div>
);
}
}
Above, the plugin has removed the tr which has a name of data-desktop and class method ending with _desktop
We have passed the env vars to the plugin as
plugins: [
[require.resolve('babel-plugin-mobile-optimizer-react'), {
"JSX_ENV": "data-desktop", // remove jsx code matching with name as data-desktop
"CLASS_METHOD_ENV": "_desktop" // remove class method ending with _desktop
}]
]
I hope this will help to write your own babel plugin. Complete code can be found on my github repo
Plugin :- babel-plugin-mobile-optimizer-react
Usage in react app :- react-labs
In the next blog i will be mentioning about debugging the babel plugin and how you can setup vscode to debug it.
Posted on June 22, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.