• Babel 插件通关秘籍
  • Git 原理详解及实用指南
  • Nest 通关秘籍
  • React 通关秘籍
  • TypeScript 全面进阶指南
  • TypeScript 类型体操通关秘籍
  • 现代CSS
  • Babel 插件通关秘籍
  • Git 原理详解及实用指南
  • Nest 通关秘籍
  • React 通关秘籍
  • TypeScript 全面进阶指南
  • TypeScript 类型体操通关秘籍
  • 现代CSS
  • Babel 插件通关秘籍

    • 1.Babel 的介绍
    • 2.Babel 的编译流程
    • 3.Babel 的 AST
    • 4.Babel 的 API
    • 5.实战案例:插入函数调用参数
    • 6.JS Parser 的历史
    • 7.traverse 的 path、scope、visitor
    • 8.Generator 和 SourceMap 的奥秘
    • 9.Code- Frame 和代码高亮原理
    • 10.Babel 插件和 preset
    • 11.Babel 插件的单元测试
    • 12.Babel 的内置功能(上)
    • 13.Babel 的内置功能(下)
    • 14.Babel 配置的原理
    • 15.工具介绍:VSCode Debugger 的使用
    • 16.实战案例:自动埋点
    • 17.实战案例: 自动国际化
    • 18.实战案例:自动生成 API 文档
    • 19.实战案例: Linter
    • 20.实战案例: 类型检查
    • 21.实战案例: 压缩混淆
    • 22.实战案例: JS 解释器
    • 23.实战案例: 模块遍历
    • 24.Babel Macros
    • 25.如何调试 Babel 源码?
    • 26.手写 Babel:思路篇
    • 27.手写 Babel: parser 篇
    • 28.手写 Babel: traverse 篇
    • 29.手写 Babel: traverse -- path篇
    • 30.手写 Babel: traverse -- scope篇
    • 31.手写 Babel: generator篇
    • 32.手写 Babel: core篇
    • 33.手写 Babel: cli篇
    • 34.手写 Babel: 总结
    • 35.小册总结
    • 36.加餐:会了 babel 插件,就会写 prettier 插件

学到这里,我们对 babel 插件的写法和 babel 内置的 preset 的实现都有了比较多的了解,但是对 babel 本身的实现可能还不是特别清晰。所以,我们通过写一个简单的 babel 来深入探索下 babel 的实现原理。

希望完成这个案例之后,能够帮你真正掌握 babel。

整体思路

babel 的编译流程

我们知道,babel 的主要编译流程是 parse、transform、generate。

  • parse 是把源码转成 AST
  • transform 是对 AST 做增删改
  • generate 是打印 AST 成目标代码并生成 sourcemap

babel 7 把这些功能的实现放到了不同的包里面:

  • @babel/parser 解析源码成 AST,对应 parse 阶段
  • @babel/traverse 遍历 AST 并调用 visitor 函数,对应 transform 阶段
  • @babel/generate 打印 AST,生成目标代码和 sorucemap,对应 generate 阶段

其中,遍历过程中需要创建 AST,会用到:

  • @babel/types 创建、判断 AST
  • @babel/template 根据模块批量创建 AST

上面是每一个阶段的功能, babel 整体功能的入口是在:

  • @babel/core 解析配置、应用 plugin、preset,整体整体编译流程

插件和插件之间有一些公共函数,这些都是在:

  • @babel/helpers 用于转换 es next 代码需要的通过模板创建的 AST,比如 _typeof、_defineProperties 等
  • @babel/helper-xxx 其他的插件之间共享的用于操作 AST 的公共函数

当然,除了编译期转换的时候会有公共函数以外,运行时也有,这部分是放在:

  • @babel/runtime 主要是包含 corejs、helpers、regenerator 这 3 部分:
    • helper: helper 函数的运行时版本(不是通过 AST 注入了,而是运行时引入代码)
    • corejs: es next 的 api 的实现,corejs 2 只支持静态方法,corejs 3 还支持实例方法
    • regenerator:async await 的实现,由 facebook 维护

(babel 做语法转换是自己实现的 helper,但是做 polyfill 都不是自己实现的,而是借助了第三方的 corejs、regenerator)

  • @babel/cli babel 的命令行工具,支持通过 glob 字符串来编译多个文件

我们要实现哪些包

上面介绍的是 babel 完成功能所内置的一些包,我们如果要写一个简易的 babel,也得实现这些包,但可以做一些简化。

  • parser 包是肯定要实现的,babel parser 是基于 acorn fork 的,我们也基于 acorn,做一点扩展。完成从源码到 AST 的转换。
  • traverse 包是对 AST 的遍历,需要知道不同类型的 AST 都遍历哪些 key,这些是在 @babel/types 包里面定义的,我们也用类似的实现方式,并且会调用对应的 visitor,实现 path 和 path.scope 的一些 api 然后传入。
  • generate 包是打印 AST 成目标代码,生成 sourcemap。打印这部分每个 AST 类型都要写一个对应的函数来处理,生成 sourcemap 使用 source-map 这个包,关联 parse 时记录的 loc 和打印时计算的位置来生成每一个 mapping。
  • types 包用于创建 AST,会维护创建和判断各种 AST 的 api,并且提供每种 AST 需要遍历的属性是哪些,用于 traverse 的过程
  • template 包是批量创建 AST 的,这里我们实现一个简单的版本,传入字符串,parse 成 AST 返回。
  • core 包是整体流程的串联,支持 plugins 和 presets,调用插件,合并成最终的 visitors,然后再 traverse。
  • helper 包我们也会实现一个,因为支持了 plugin,那么中有一些公共的函数可以复用
  • runtime 包我们也提供一下,不过只加入一些用于做语法转换的辅助函数就好了
  • cli 包 实现一个命令行工具,来调用 core 包的功能

这是我们大概会做的事情,把这些都实现一遍就算一个比较完整的 babel 了。实现的过程中更能加深我们对 babel、对转译器的认识,不只是掌握 babel 本身。

总结

这一节讲了下整体的思路,后面章节会一步步实现,希望能够帮助大家深入 babel 的本质。

上次更新: 6/21/25, 9:42 AM
贡献者: YNight
Prev
25.如何调试 Babel 源码?
Next
27.手写 Babel: parser 篇