第 100 期 - Babel 的架构与 ECMAScript 标准化
摘要
本文介绍了 Babel 的基本情况,包括它是什么、转译过程、微内核架构以及相关模块,还阐述了 ECMAScript 标准化相关内容,如发展历程、版本、阅读方式等,最后总结了 Babel 在设计思路和与标准规范配合方面值得学习之处。
一、Babel 简介
Babel 是 JavaScript 转译器,它不同于编译器,转译是将一种语言转换为不同版本或者抽象程度相同的语言。例如它可以把高版本的 ECMAScript 语法转译为低版本语法,从而能在低版本浏览器、低版本 Node.js 等环境运行。
- Babel 的功能实现:
- 语法转译(Syntax):Babel 支持识别高版本语法,并通过插件将源码从高版本语法转译为低版本语法,像箭头函数
() => {}
会被转为普通函数function() {}
,const / let
转译为var
。 - 添加 API Polyfill:有些运行时相关的 API,语法转译无法解决它们对低版本浏览器等环境的兼容性问题,Babel 会与
core - js
等工具配合,例如[1, 2, 3].include
、Promise
等 API,如果目标环节可能不支持原生的include / Promise
,Babel 会在转译结果中嵌入其自定义实现。
- 语法转译(Syntax):Babel 支持识别高版本语法,并通过插件将源码从高版本语法转译为低版本语法,像箭头函数
- 使用方式:有多种方式可以使用 Babel,如命令行(
babel - cli
、babel - node
)、浏览器(babel - standalone
)、API 调用(babel - core
)、webpack loader
(babel - loader
)等。 - 转译过程:和多数转译器相同,Babel 运行的生命周期主要是 3 个阶段:解析、转换、代码生成。
- 解析(Parsing):
Code1 ==> 抽象语法树 1
,这个过程包括词法解析和语法解析。词法解析阶段,代码字符串被解析为token
令牌数组,其元素是包含代码字符碎片的值、位置、类型等信息的对象,为语法解析做准备;语法解析阶段,token
令牌数组被解析为结构化的抽象语法树对象(AST),主要由babel - parser
完成。 - 转换(Transformation):
AST1 ==> AST2
,Babel 生成 AST 后,会对 AST 进行遍历,各类插件对原 AST 对象进行增删改查等操作,从而修改 AST 结构。 - 代码生成(Generation):
AST2 ==> Code2
,Babel 将修改后的 AST 对象转成目标代码字符串,由babel - generator
完成该阶段的主要功能。
- 解析(Parsing):
二、Babel 微内核架构
- 微内核架构:Babel 采用微内核架构,其内核保留核心功能,其余功能利用外部工具和插件机制实现,体现了“开放 - 封闭”的设计原则。
- 模块分类:
- 转译模块:位于 Babel 微内核架构的“微内核”部分,主要负责代码转译(即上述的“解析 - 转换 - 代码生成”过程),包括
babel - parser
、babel - traverse
、babel - generator
。babel - parser
:负责将代码字符串转为 AST 对象,但它本身不做转换操作,且内置对ESNext/TypeScript/JSX/Flow
最新版本语法的支持,很多默认不开启,目前没有开放插件机制扩展新语法。babel - traverse
:在转译过程中负责遍历 AST 节点,根据配置的plugins/presets
,在遍历过程中对各个 AST 节点进行增删改查的操作,这是一个深度优先遍历的过程。babel - generator
:负责将 AST 节点转为代码字符串,同时也可以生成source - map
。
- 插件模块:包括
plugins
、presets
。- 语法插件:功能是作为“开关”,配置是否开启
babel - parser
的某些语法转译功能,在 Babel 源码中以babel - plugin - syntax
开头,例如babel - plugin - syntax - decorators
负责开启babel - parser
对装饰器的语法支持。 - 转换插件:负责转换 AST 节点,在 Babel 源码中以
babel - plugin - transform
开头,会提供一个叫做“Visitor”的对象,在回调函数里对节点进行操作。 - Presets:是插件集,在 Babel 源码中以
babel - preset
开头,如babel - preset - env
、babel - preset - react
等,方便在实际开发中一次性引入多个插件功能。并且plugins
在presets
之前运行,plugins
按照数组正序执行,presets
按照数组倒序执行。
- 语法插件:功能是作为“开关”,配置是否开启
- 工具模块:提供 Babel 相关模块所需的各类工具。
babel - core
:对外提供 Babel 多项功能的 API,转译类的 API 均提供了同步和异步版本。babel - cli
:Babel 的命令行工具,可以直接转译文件夹/文件。babel - standalone
:提供浏览器下转译的方案,内置了所有 Babel 插件,体积较大且转译需要时间,适合开发、学习使用,不适合生产环境。babel - node
:提供在命令行执行高级语法的环境。babel - register
:通过拦截node require
方法,为node
运行时引入 Babel 的转译能力。babel - loader
:是利用babel - core
的 API 封装的webpack loader
,用于webpack
构建过程。babel - types
:集成了节点校验、增删改查等功能,是 Babel 核心模块开发、插件开发等场景下不可或缺的工具。babel - template
:模板引擎,负责将代码字符串转为 AST 节点对象。babel - code - frame
:负责打印出错的代码位置。babel - highlight
:向控制台输出有颜色的代码片段,可识别 JavaScript 中的不同类型词法单元并显示不同颜色。
- 运行时相关模块:关注转译产物的运行时环境,对运行时提供 API polyfill、代码优化等,涉及
babel - preset - env
、babel - plugin - transform - runtime
、babel - runtime
、babel - runtime - corejs2/3
、core - js
等子包。通过具体案例展示了如何配置相关内容来转译源码中的语法和 API 部分,并优化转译产物。
- 转译模块:位于 Babel 微内核架构的“微内核”部分,主要负责代码转译(即上述的“解析 - 转换 - 代码生成”过程),包括
三、标准化
- ECMAScript:
- 发展历程:JavaScript 诞生于 1995 年,1996 年微软模仿实现了 JScript,随后 Netscape 公司推动 JavaScript 标准化。
Ecma International
负责制定 JavaScript 标准语言规范ECMAScript
,其下的TC39
负责迭代和发展ECMAScript
,成员由主流浏览器厂商代表组成,通过会议讨论决议相关事项。 - 版本与制作过程:
ECMAScript
经历多个版本,其标准制作过程包含Stage 0
到Stage 4
共 5 个阶段,特性进入Stage - 4
后才可能被加入标准,还需ECMA General Assembly
表决通过才能进入下一次标准。 - 如何阅读:
ECMAScript
的规格可在ECMA
国际标准组织官方网站免费下载和在线阅读。不同版本有各自网址,虽然章节数量不同但分布有规律。一般开发者无需通读,遇到奇怪问题时可阅读解决,例如通过阅读ECMAScript 11.0
规格可了解关键词、保留字、全局对象等内容,以用于代码的相关处理。
- 发展历程:JavaScript 诞生于 1995 年,1996 年微软模仿实现了 JScript,随后 Netscape 公司推动 JavaScript 标准化。
- Web 标准:在解决 API Polyfil 时,Babel 配合使用的
core - js
除了提供ECMAScript
标准下的 JavaScript API 实现,也提供DOM/URL
等实现,DOM/URL
所属的 web 标准由W3C/WHATWG
制定,二者目前是合作关系,WHATWG
维护HTML
和DOM
标准,W3C
在HTML
部分工作集中在XHTML/XML
上。
四、总结
本文介绍了 Babel 的相关内容,包括概述、微内核架构、ECMAScript 标准化方面的设计思想和部分实现原理。虽然 Babel 近期迭代变化不大,但它的设计思路以及与标准规范的配合方式值得学习。
扩展阅读
Made by 捣鼓键盘的小麦 / © 2025 Front Talk 版权所有