
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 .