What is Babel?
- Build tools, such as
webpack - Via the CLI,
babel-cli - Directly through
babel-node
^ If you've ever used these Facebook technologies, like React, React Native, Jest (the JavaScript testing framework) or Flow (the genesis of the Redux statement management pattern), you will have used Babel under the covers.
^ So whilst you probably will never need to write a Babel plugin, hopefully this talk can give you a better understanding of this ecosystem and how it can be used in your own projects.
.babelrc from create-react-native-app:
{
"presets": [
"babel-preset-react-native-stage-0/decorator-support"
],
"env": {
"development": {
"plugins": [
"transform-react-jsx-source"
]
}
}
}
^ The babel-preset-react-native-stage-0 is a collection of plugins (and also the babel-preset-react-native preset).
^ decorator-support is a file in the package that just exports the required preset and extra plugins.
^ The transform-react-jsx-source is described as "Adds source file and line number to JSX elements".
- Preset
- Set of plugins
- Plugin
- Transform & Syntax
^ Transform plugins can enable the required syntax plugins with the inherits in their definition.
--
5 + 2
5 + 2
"expression": {
"type": "BinaryExpression",
...
},
"left": {
"type": "Literal",
"value": 5,
...
},
"operator": "+",
"right": {
"type": "Literal",
"value": 2,
...
}
}^ A Babel transformer will the traverse the AST, calling each method in the visitor object that is of a corresponding type.
- Input & output should be valid (Babylon-supported) JS ✅
- tc39 stage features
- Flow, JSX, etc
- Doesn't support third-party syntax plugins ❌
^ If you're just about to quit your job, you should sneak this in.
^ Simply changes all of the pluses to minuses.
module.exports = function({ types: t }) {
return {
name: 'transform-fun-chaos',
visitor: {
BinaryExpression(path) {
if (path.node.operator !== '+') return
path.replaceWith(
t.binaryExpression('-', path.node.left, path.node.right)
);
}
}
};
};^ And because these plugins are themselves JavaScript, we can execute code, such as randomly changing plusses to minuses.
module.exports = function({ types: t }) {
return {
name: 'transform-fun-chaos',
visitor: {
BinaryExpression(path) {
if (path.node.operator !== '+') return
if (Math.random() > 0.5) {
path.replaceWith(
t.binaryExpression('-', path.node.left, path.node.right)
);
}
}
}
};
};^ Or changing them after 5 PM.
module.exports = function({ types: t }) {
return {
name: 'transform-fun-chaos',
visitor: {
BinaryExpression(path) {
if (path.node.operator !=='+') return
const afterFivePM = (new Date()).getHours() >= 17
if (afterFivePM) {
path.replaceWith(
t.binaryExpression('-', path.node.left, path.node.right)
);
}
}
}
};
};NaN == NaN // false
NaN === NaN // false
Number.isNan(NaN) // trueWe can write a plugin which automatically converts NaN equality checks to use the correct function
module.exports = function({ types: t }) {
return {
name: 'transform-nan-equality',
visitor: {
BinaryExpression(path) {
if (
(path.node.operator !== '==' && path.node.operator !== '===') &&
(path.node.left.name !== t.identifier('NaN').name) &&
(path.node.right.name !== t.identifier('NaN').name)) {
return
}
if (path.node.left.name === t.identifier('NaN').name) {
path.replaceWithSourceString(`isNan(${path.node.right.name})`)
} else if (path.node.right.name === t.identifier('NaN').name) {
path.replaceWithSourceString(`isNan(${path.node.left.name})`)
}
}
}
};
};^ Whilst this was an interesting exercise, the real value of these plugins is that the Babel ecosystem can be extended as language features are added and evolve. Performing source code modifications such as above would be better handled by a linter.





