Mastering AST: Transform JavaScript Code with Babel and Esprima
This article explains how to use AST in JavaScript by introducing three essential components—a parser, a traverser, and a code generator—showcasing practical examples with esprima and Babel to parse, modify, and regenerate code, and exploring advanced use cases such as removing console statements, variable obfuscation, arrow‑function conversion, tree‑shaking, and generating SVG flowcharts, while also highlighting AST applications in other languages.
Three Key Points of AST Application
Need a parser to convert code to AST.
Need a traverser to walk and manipulate AST nodes.
Need a code generator to convert AST back to code.
esprima and babel
Common tools that satisfy the three points are esprima and babel.
esprima related packages and usage:
const esprima = require('esprima'); // code => ast
const estraverse = require('estraverse'); // ast traversal
const escodegen = require('escodegen'); // ast => code
let code = 'const a = 1';
const ast = esprima.parseScript(code);
// traversal example...
const transformCode = escodegen.generate(ast);babel related packages and usage:
const parser = require('@babel/parser'); // code => ast
const traverse = require('@babel/traverse').default; // ast traversal, node CRUD, scope handling
const generate = require('@babel/generator').default; // ast => code
const t = require('@babel/types'); // utility library for AST nodes
let code = `function square(n) {
console.log(n);
console.warn(n);
return n * n;
}`;
let ast = parser.parse(code);
// traversal example...Babel is recommended over esprima due to better ecosystem and documentation.
Using Babel Tools to Operate AST
@babel/parser– parse code to AST @babel/traverse – traverse AST, modify nodes, handle scopes @babel/generator – generate code from AST @babel/types – Lodash‑style utilities for AST node construction and validation
More APIs can be found in the Babel handbook.
Case 1: Remove console.log()
Implementation code:
const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const generate = require('@babel/generator').default;
let sourceCode = `function square(n) {
console.log(n);
console.warn(n);
return n * n;
}`;
let ast = parser.parse(sourceCode);
traverse(ast, {
CallExpression(path) {
const { callee } = path.node;
if (callee.type === 'MemberExpression' &&
callee.object.name === 'console' &&
callee.property.name === 'log') {
path.remove(); // beware of global.console.log()
}
}
});
console.log(generate(ast).code);Result:
function square(n) {
// console.log removed
console.warn(n);
return n * n;
}Key points: how to traverse specific nodes, identify CallExpression, and use path.remove().
Case 2: Variable obfuscation
Implementation code:
const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const generate = require('@babel/generator').default;
const t = require('@babel/types');
let sourceCode = `function square(number) {
console.warn(number);
return number * number;
}`;
let ast = parser.parse(sourceCode);
traverse(ast, {
FunctionDeclaration(path) {
const uid = path.scope.generateUidIdentifier('a');
path.scope.rename('number', uid.name);
}
});
console.log(generate(ast).code);Result:
function square(_a) {
console.warn(_a);
return _a * _a;
}Key points: path.scope provides scope information, you can generate unique identifiers and rename variables.
Case 3: Convert arrow functions and drop unused parameters
Implementation code:
const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const generate = require('@babel/generator').default;
const t = require('@babel/types');
let sourceCode = `new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve(1); },200) })`;
let ast = parser.parse(sourceCode);
traverse(ast, {
ArrowFunctionExpression(path) {
const { id, params, body } = path.node;
const usedParams = params.filter(p => path.scope.bindings[p.name].referenced);
path.replaceWith(t.functionExpression(id, usedParams, body));
}
});
console.log(generate(ast).code);Result shows the arrow function turned into a regular function with only the used parameters.
Case 4: Tree‑shaking in a JD mini‑program
Implementation code removes unused exported functions:
const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const generate = require('@babel/generator').default;
const t = require('@babel/types');
let sourceCode = `export function square(x){ return x*x; }
export function cube(x){ return x*x*x; }`;
let ast = parser.parse(sourceCode);
traverse(ast, {
ExportNamedDeclaration(path) {
const decl = path.node.declaration;
if (decl.type === 'FunctionDeclaration') {
const name = decl.id.name;
const binding = path.scope.bindings[name];
if (binding.references === 1) { // only the export itself
path.remove();
}
}
}
});
console.log(generate(ast).code);Result keeps only the used export.
Case 5: Convert code to SVG flowchart
Uses the open‑source project js-code-to-svg-flowchart to transform JavaScript code into an SVG diagram. A live demo is available.
AST in other languages
Beyond JavaScript, AST is used for HTML, CSS, SQL, and other languages. Parsers for these languages are listed on the AST Explorer site.
Conclusion
AST is everywhere: Babel, Webpack, ESLint, Taro, etc. Understanding and leveraging AST can help you build powerful tools and improve your projects.
References [1] Babel handbook: https://github.com/jamiebuilds/babel-handbook/blob/master/translations/zh-Hans/plugin-handbook.md [2] js-code-to-svg-flowchart: https://github.com/Bogdan-Lyashenko/js-code-to-svg-flowchart [3] Demo: https://bogdan-lyashenko.github.io/js-code-to-svg-flowchart/docs/live-editor/index.html
WecTeam
WecTeam (维C团) is the front‑end technology team of JD.com’s Jingxi business unit, focusing on front‑end engineering, web performance optimization, mini‑program and app development, serverless, multi‑platform reuse, and visual building.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
