必须统一使用 babel-parser 解析和 @babel/generator 生成以确保 AST 元信息完整、修改精准;避免混用工具链导致节点结构不匹配、注释丢失或生成无效代码。

AST 修改前必须确认 parser 和 generator 是否匹配
直接用 acorn 解析、再用 escodegen 生成,大概率会丢掉注释或格式,甚至生成无效代码。关键不是“能跑”,而是“改得准、不污染”。推荐统一使用 babel-parser(即 @babel/parser)解析,再用 @babel/generator 生成 —— 它们共享同一套 AST 规范,且保留了 comments、leadingComments、trailingComments 等元信息。
常见错误现象:TypeError: Cannot read property 'name' of undefined,往往是因为你用了不同工具链的 AST 节点结构(比如 estree vs Babel 的 Identifier 字段名差异);或者修改后没调用 generate() 就直接写回文件,结果写入的是原始源码而非 AST 变更后的结果。
- 检查 AST 节点类型优先用
node.type === "ImportDeclaration",而不是依赖字段存在性 - 修改节点时避免直接赋值
node.source.value = "new/path",应先深拷贝或用babel-types.cloneNode()防止副作用 - 若需保留换行/缩进,启用
@babel/generator的retainLines: true和compact: false
批量重写 import 路径时别硬编码字符串替换
用正则全局替换 import ... from "./utils/" 看似快,但会误伤字符串字面量、注释、JSX 属性值,甚至破坏模板字符串结构。正确做法是遍历 ImportDeclaration 和 ExportNamedDeclaration 节点,只改 node.source.value,并做路径规范化(path.posix.resolve() 或 url.pathToFileURL())。
使用场景:从相对路径迁移到别名(~components),或统一升级包版本导致路径变更(如 lodash-es → lodash 子模块拆分)。
立即学习“前端免费学习笔记(深入)”;
使用 Puppeteer + Chrome 将 HTML 渲染为中文 PDF,自动处理图表等待、Tab 展开、动画、测高、白边消除、防分页,适用于看板、报表、网页和交互图表转 PDF。
- 注意
node.source是StringLiteral节点,不能直接赋字符串,要 new 一个新节点:t.stringLiteral("new-path") - 动态路径拼接时,用
path.join()而非+,避免 Windows 下反斜杠引发解析失败 - 如果目标路径含变量(如
process.env.NODE_ENV),不要在 AST 层展开,应留到构建时由打包器处理
修改 JSX 属性时小心 props 合并逻辑
JSX 中的 className、style、自定义 prop 如 data-testid 常被多处注入。直接覆盖 node.openingElement.attributes 会清掉已有属性。正确方式是用 t.jSXAttribute() 构造新属性,并用 attributes.push() 插入,或用 t.jsxSpreadAttribute() 注入对象展开。
性能影响:每次新增 JSX 属性都触发一次完整 AST 重建,若处理千行 JSX 文件,建议用 visitor 的 enter 阶段做增量修改,避免嵌套遍历。
- 判断属性是否存在用
node.openingElement.attributes.find(a => t.isJSXAttribute(a) && a.name.name === "className") - 修改
style对象时,不要替换整个JSXExpressionContainer,而应在表达式内部操作其expression(通常是ObjectExpression) - 若需插入条件属性(如
{...props}后加data-uid),确保插入位置在 spread 之后,否则会被覆盖
本地开发时 watch + transform 容易漏触发重编译
用 chokidar 监听 .html 或 .js 文件变化后执行 AST 修改,但常见问题:修改后的文件未触发下游构建(如 webpack/vite),因为文件 mtime 没变,或 watcher 忽略了写入事件。根本原因是 Node.js 的 fs.writeFile() 默认不更新 atime/mtime,且某些编辑器(VS Code)会先删后写,导致短暂缺失文件。
可给出简短示例:
fs.writeFileSync(filepath, outputCode, { flag: "w" }); // 必须显式用 "w",避免 append 模式残留旧内容
- 写入前加
fs.chmodSync(filepath, 0o644)防止权限丢失导致构建跳过 - watch 时监听
change和add两个事件,不只靠change - 若用 rollup 插件,优先走
transform钩子而非外部脚本,避免绕过缓存机制
复杂点在于:HTML 中内联 <script> 和外部 .js 引用需统一处理策略;容易被忽略的是 sourceMap 映射偏移 —— AST 修改后未重生成 sourcemap,调试时断点会错位。


















