
Hoy compartiré con ustedes una guía paso a paso sobre cómo escribir su complemento babel . Puede usar este conocimiento para automatizar ediciones, refactorización o generación de código.
¿Qué es babel?
Babel es un compilador de JavaScript que se utiliza principalmente para convertir el código ECMAScript 2015+ compatible con versiones anteriores de navegadores o entornos actuales y anteriores. Babel utiliza un sistema de complementos para convertir el código, por lo que cualquiera puede escribir su propio complemento.
, AST( ).
AST?
, :
, AST . JavaScript, AST JavaScript estree.
AST . AST babel, .
, AST, .
babel ?
, babel :
import { parse } from '@babel/parser';
import traverse from '@babel/traverse';
import generate from '@babel/generator';
const code = 'const n = 1';
const ast = parse(code);
traverse(ast, {
enter(path) {
if (path.isIdentifier({ name: 'n' })) {
path.node.name = 'x';
}
},
});
const output = generate(ast, code);
console.log(output.code);
@babel/core
. @babel/parser
, @babel/traverse
, @babel/generator
@babel/core
.
AST, AST .
-> AST -> AST ->
, babel API :
import babel from '@babel/core';
const code = 'const n = 1';
const output = babel.transformSync(code, {
plugins: [
function myCustomPlugin() {
return {
visitor: {
Identifier(path) {
if (path.isIdentifier({ name: 'n' })) {
path.node.name = 'x';
}
},
},
};
},
],
});
console.log(output.code);
babel n
x
, ?
myCustomPlugin
. npm babel !
: ", babel , ...". , .
1.
:
:
function greet(name) {
return 'Hello ' + name;
}
console.log(greet('tanhauhau'));
:
function teerg(eman) {
return 'H' + 'e' + 'l' + 'l' + 'o' + ' ' + eman;
}
console.log(teerg('t' + 'a' + 'n' + 'h' + 'a' + 'u' + 'h' + 'a' + 'u'));
console.log
, , . ( !)
2. AST
babel AST explorer, AST:

AST, , .
, :
- Identifier
- StringLiteral .
3. AST
babel AST explorer, :

AST .
'H' + 'e' + 'l' + 'l' + 'o' + ' ' + eman
(BinaryExpression
) (StringLiteral
)
4.
:
function myCustomPlugin() {
return {
visitor: {
Identifier(path) {
},
},
};
}
visitor.
, babel AST . visitor
, , babel .
visitor
:
function myCustomPlugin() {
return {
visitor: {
Identifier(path) {
console.log('');
},
StringLiteral(path) {
console.log(' ');
},
},
};
}
,
babel :
, Identifer(path) {}
. path
node
, ?
babel, path
, , , , .. path
, replaceWith
, insertBefore
, remove
, AST .
path
babel Jamie Kyle
.
babel AST explorer, name
, , :
Identifier(path) {
path.node.name = path.node.name
.split('')
.reverse()
.join('');
}
:
function teerg(eman) {
return 'Hello ' + eman;
}
elosnoc.gol(teerg('tanhauhau'));
console.log . ?
AST:

console.log
MemberExpression
, c object
— "console"
property
— "log"
, MemberExpression
, :
if (
!(
path.parentPath.isMemberExpression() &&
path.parentPath
.get('object')
.isIdentifier({ name: 'console' }) &&
path.parentPath.get('property').isIdentifier({ name: 'log' })
)
) {
path.node.name = path.node.name
.split('')
.reverse()
.join('');
}
}
, !
function teerg(eman) {
return 'Hello ' + eman;
}
console.log(teerg('tanhauhau'));
, Identifier
console.log
MemberExpression
? Identifier.name === 'console' || Identifier.name === 'log'
?
, console
or log
:
const log = 1;
isMemberExpression
isIdentifier
? @babel/types isXxxx
, anyTypeAnnotation
isAnyTypeAnnotation
. ,
BinaryExpression
.
AST, [@babel/types](https://babeljs.io/docs/en/babel-types)
:
StringLiteral(path) {
const newNode = path.node.value
.split('')
.map(c => babel.types.stringLiteral(c))
.reduce((prev, curr) => {
return babel.types.binaryExpression('+', prev, curr);
});
path.replaceWith(newNode);
}
StringLiteral
, path.node.value
, c StringLiteral
BinaryExpression
. StringLiteral
.
… ! , :
RangeError: Maximum call stack size exceeded
?
, StringLiteral
StringLiteral
, StringLiteral
. StringLiteral
StringLiteral
, babel , , .
, babel StringLiteral
newNode
, ?
path.skip()
:
StringLiteral(path) {
const newNode = path.node.value
.split('')
.map(c => babel.types.stringLiteral(c))
.reduce((prev, curr) => {
return babel.types.binaryExpression('+', prev, curr);
});
path.replaceWith(newNode);
path.skip();
}
… !
babel:
const babel = require('@babel/core');
const code = `
function greet(name) {
return 'Hello ' + name;
}
console.log(greet('tanhauhau')); // Hello tanhauhau
`;
const output = babel.transformSync(code, {
plugins: [
function myCustomPlugin() {
return {
visitor: {
StringLiteral(path) {
const concat = path.node.value
.split('')
.map(c => babel.types.stringLiteral(c))
.reduce((prev, curr) => {
return babel.types.binaryExpression('+', prev, curr);
});
path.replaceWith(concat);
path.skip();
},
Identifier(path) {
if (
!(
path.parentPath.isMemberExpression() &&
path.parentPath
.get('object')
.isIdentifier({ name: 'console' }) &&
path.parentPath.get('property').isIdentifier({ name: 'log' })
)
) {
path.node.name = path.node.name
.split('')
.reverse()
.join('');
}
},
},
};
},
],
});
console.log(output.code);
, :
- AST
- AST
, babel GitHub babel.
https://github.com/babel/babel, babel-plugin-transform-*
babel-plugin-proposal-*
, -, babel nullish coalescing operator, optional chaining .