We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Babel是JavaScript编译器。
通过Babel,开发者可以自由使用下一代JavaScript语法。高版本JavaScript语法将被转译为低版本语法,以便顺利运行在各类环境:低版本浏览器、低版本Node.js等。
本文,我们从全局层面理解下Babel的运行原理,如生命周期、生态、开发模式等。
抽象语法树(Abstract Syntax Tree,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。
AST是树形对象,以结构化的形式表示编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。
之所以说语法树是“抽象”的,是因为这里的语法并不会表示出真实语法中出现的每个细节。
和抽象语法树相对的是具体语法树(通常称作分析树)。一般的,在源代码的翻译和编译过程中,语法分析器创建出分析树,然后从分析树生成AST。
Babel是一个典型的"输入-输出"工具。
Babel接收一段JavaScript代码(通常是高版本JavaScript),经过一系列处理,转为目标代码(通常是低版本JavaScript)并输出。
图解如下:
有多种方式可以使用Babel,如:命令行(babel-cli)、方法调用(babel-core)、webpack loader(babel-loader)等。
和多数编译器相同,Babel运行的生命周期主要是3个阶段,如下图:
解析(Parsing)
该阶段,代码字符串被转为抽象语法树(AST)。
解析过程包括2个环节:词法解析、语法解析。
词法解析阶段,代码字符串被解析为token令牌数组,数组项包括:代码字符碎片的值、位置、类型等信息。
语法解析阶段,token令牌数组被解析为抽放语法树(AST)。
babel-parser完成该阶段的主要功能。
转换(Transformation)
这个阶段,Babel通过各类语法插件、转换插件对AST进行遍历、增删改等操作,转为目标AST。
完成该阶段主要功能的包括以下工具:
代码生成(Generation)
Babel将修改后的AST转为目标代码字符串。
babel-generator完成该阶段的主要功能。
我们把范围扩展一下,了解Babel是怎样运行的,如下图:
Babel产品包括多个模块:
从图1-3-1中可以看出,babel-core作为Babel的核心模块,主要有2个功能:
任务调度
对外暴露各类API
Babel的对外工具babel-cli、babel-loader等均使用了babel-core的一些API,举个例子:
babel.parse()
babel.generate()
我们将以一个章节介绍babel-core的各种细节。
面向外部开发者,Babel提供了多种工具,如babel-cli、babel-loader等。
babel-cli帮助开发者以命令行的形式进行文件编译,并支持各种配置,其功能非常强大。
我们专门以一章的篇幅介绍babel-cli,从中可以吸取很多不错的开发经验。
babel-loader是专门为webpack使用的loader,作用也是进行代码编译。
babel-loader为用户提供了多种配置项,且针对webpack环境提供了性能优化等针对性处理。
我们在后续章节专门介绍babel-loader。
babel-core有JavaScript代码解析所需的各项功能,可以作为一个独立工具对外提供服务。
const babel = require('@babel/core');
比如:
babel.parse
babel.transform
Babel支持多种配置方式。
下文中所述的"项目根目录",指的是package.json文件所在的目录。
package.json
babel.config.js
在项目根目录创建babel.config.js文件,其内容如下:
module.exports = function(api) { return { presets: [ ... ], plugins: [ ... ] }; };
.babelrc
在项目根目录创建.babelrc文件,其内容如下:
{ "presets": [ ... ], "plugins": [ ... ] }
.babelrc.js
在项目根目录创建.babelrc.js文件,其内容如下:
module.exports = { presets: [ ... ], plugins: [ ... ] };
Babel的配置信息可以写在package.json内:
"babel": { "presets": [ ... ], "plugins": [ ... ] }
丰富的插件,帮助Babel成为一个非常成功的编译工具。
对AST的遍历、转换是Babel编译的核心功能,但Babel本身并不参与该过程,将这些功能作为插件引入到运行时。
具体来说,babel-core作为核心工具,不提供对AST的修改逻辑,通过调用各类插件,实现对AST的修改。
1.6节所述的配置项,也基本围绕Babel的插件生态进行。
Babel的插件分为语法插件和转换插件。
语法插件
Babel有一个细节,babel-parser负责将JavaScript代码转为抽象语法树(AST),它支持全面识别ESNext、TypeScript、JSX等语法,目前由Babel团队开发维护,不支持插件化。
Babel插件生态中的语法插件,其功能就是作为"开关",配置是否开启babel-parser的某些语法编译功能。
语法插件在Babel源码中,以babel-plugin-syntax开头。
babel-plugin-syntax
举个例子:
babel-plugin-syntax-decorators
负责开启babel-parser对装饰器的语法支持。
babel-plugin-syntax-dynamic-import
负责开启babel-parser对import语句的语法支持。
babel-plugin-syntax-jsx
负责开启babel-parser对jsx语法的支持。
转换插件
转换插件就是社区里常说的Babel插件,负责对AST进行遍历和转换。
转换插件在Babel源码中,以babel-plugin-transform开头。
babel-plugin-transform
babel-plugin-
Babel插件的功能是细粒度的,大部分插件承担了单一功能。
而在实际开发过程中,往往需要支持对各类语法的支持。此时,有两种做法:
很显然,第一种做法是相对麻烦的。针对第二种做法,Babel提供了插件集preset。
preset在Babel源码中,以babel-preset开头。
babel-preset
例如,Babel已经提供了几种常用的preset供开发者使用:
babel-preset-env
babel-preset-react
babel-preset-flow
babel-preset-typescript
1.7.3 插件运行顺序
Babel配置项中,plugins和presets均以数组的形式配置,执行时有先后顺序。
如果一个大型项目由多个独立的工程组成,该如何管理呢?
通常来说,有两种方式:
monorepo
monorepo指的是,该项目所有工程统一在一个仓库中,统一维护、发布。
目前React、Angular等均采用该方式。
multirepo
和monorepo相反,该项目的每个子工程独立运行,每个子工程相互独立,自由选择构建工具,独立发布。
二者对比如下:
Babel项目涉及的子工程很多,其采用了monorepo方式开发,并且沉淀出了自动化工具lerna,当然也有其他工具实现了monorepo。
Babel使用的lerna命令行工具中,lerna bootstrap命令负责统一安装依赖,lerna publish命令负责统一发布工程内的子项目。
lerna bootstrap
lerna publish
Babel的大部分package(如babel-core、babel-parser等)的版本号是始终一致的,这也是monorepo项目的一个特点。
monorepo项目中,开发者和使用者可以快速地查看当前工具集的统一版本,无需深入每个package查看版本并理解各自的关联关系。
本文我们从宏观层面了解了Babel的编译过程及其生态中各个模块的作用,能够初步理解Babel是怎样运行的。
其中涉及的实现原理,我们拆解到其他文章中。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
Babel是JavaScript编译器。
通过Babel,开发者可以自由使用下一代JavaScript语法。高版本JavaScript语法将被转译为低版本语法,以便顺利运行在各类环境:低版本浏览器、低版本Node.js等。
本文,我们从全局层面理解下Babel的运行原理,如生命周期、生态、开发模式等。
1.1 抽象语法树
抽象语法树(Abstract Syntax Tree,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。
AST是树形对象,以结构化的形式表示编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。
之所以说语法树是“抽象”的,是因为这里的语法并不会表示出真实语法中出现的每个细节。
和抽象语法树相对的是具体语法树(通常称作分析树)。一般的,在源代码的翻译和编译过程中,语法分析器创建出分析树,然后从分析树生成AST。
1.2 Babel的功能
Babel是一个典型的"输入-输出"工具。
Babel接收一段JavaScript代码(通常是高版本JavaScript),经过一系列处理,转为目标代码(通常是低版本JavaScript)并输出。
图解如下:
有多种方式可以使用Babel,如:命令行(babel-cli)、方法调用(babel-core)、webpack loader(babel-loader)等。
1.3 Babel生命周期
和多数编译器相同,Babel运行的生命周期主要是3个阶段,如下图:
解析(Parsing)
该阶段,代码字符串被转为抽象语法树(AST)。
解析过程包括2个环节:词法解析、语法解析。
词法解析阶段,代码字符串被解析为token令牌数组,数组项包括:代码字符碎片的值、位置、类型等信息。
语法解析阶段,token令牌数组被解析为抽放语法树(AST)。
babel-parser完成该阶段的主要功能。
转换(Transformation)
这个阶段,Babel通过各类语法插件、转换插件对AST进行遍历、增删改等操作,转为目标AST。
完成该阶段主要功能的包括以下工具:
代码生成(Generation)
Babel将修改后的AST转为目标代码字符串。
babel-generator完成该阶段的主要功能。
1.4 Babel架构
我们把范围扩展一下,了解Babel是怎样运行的,如下图:
Babel产品包括多个模块:
1.5 babel-core
从图1-3-1中可以看出,babel-core作为Babel的核心模块,主要有2个功能:
任务调度
对外暴露各类API
Babel的对外工具babel-cli、babel-loader等均使用了babel-core的一些API,举个例子:
babel.parse()
:将代码字符串转为AST。babel.generate()
:将AST转为代码字符串。我们将以一个章节介绍babel-core的各种细节。
1.6 Babel对外工具
面向外部开发者,Babel提供了多种工具,如babel-cli、babel-loader等。
1.6.1 babel-cli
babel-cli帮助开发者以命令行的形式进行文件编译,并支持各种配置,其功能非常强大。
我们专门以一章的篇幅介绍babel-cli,从中可以吸取很多不错的开发经验。
1.6.2 babel-loader
babel-loader是专门为webpack使用的loader,作用也是进行代码编译。
babel-loader为用户提供了多种配置项,且针对webpack环境提供了性能优化等针对性处理。
我们在后续章节专门介绍babel-loader。
1.6.3 babel-core
babel-core有JavaScript代码解析所需的各项功能,可以作为一个独立工具对外提供服务。
比如:
babel.parse
babel.transform
1.7 配置方式
Babel支持多种配置方式。
下文中所述的"项目根目录",指的是
package.json
文件所在的目录。babel.config.js
在项目根目录创建babel.config.js文件,其内容如下:
.babelrc
在项目根目录创建.babelrc文件,其内容如下:
.babelrc.js
在项目根目录创建.babelrc.js文件,其内容如下:
package.json
Babel的配置信息可以写在package.json内:
1.8 插件
丰富的插件,帮助Babel成为一个非常成功的编译工具。
对AST的遍历、转换是Babel编译的核心功能,但Babel本身并不参与该过程,将这些功能作为插件引入到运行时。
具体来说,babel-core作为核心工具,不提供对AST的修改逻辑,通过调用各类插件,实现对AST的修改。
1.6节所述的配置项,也基本围绕Babel的插件生态进行。
1.8.1 语法插件和转换插件
Babel的插件分为语法插件和转换插件。
语法插件
Babel有一个细节,babel-parser负责将JavaScript代码转为抽象语法树(AST),它支持全面识别ESNext、TypeScript、JSX等语法,目前由Babel团队开发维护,不支持插件化。
Babel插件生态中的语法插件,其功能就是作为"开关",配置是否开启babel-parser的某些语法编译功能。
语法插件在Babel源码中,以
babel-plugin-syntax
开头。举个例子:
babel-plugin-syntax-decorators
负责开启babel-parser对装饰器的语法支持。
babel-plugin-syntax-dynamic-import
负责开启babel-parser对import语句的语法支持。
babel-plugin-syntax-jsx
负责开启babel-parser对jsx语法的支持。
转换插件
转换插件就是社区里常说的Babel插件,负责对AST进行遍历和转换。
转换插件在Babel源码中,以
babel-plugin-transform
开头。举个例子:
babel-plugin-
1.8.2 preset
Babel插件的功能是细粒度的,大部分插件承担了单一功能。
而在实际开发过程中,往往需要支持对各类语法的支持。此时,有两种做法:
很显然,第一种做法是相对麻烦的。针对第二种做法,Babel提供了插件集preset。
preset在Babel源码中,以
babel-preset
开头。例如,Babel已经提供了几种常用的preset供开发者使用:
babel-preset-env
babel-preset-react
babel-preset-flow
babel-preset-typescript
1.7.3 插件运行顺序
Babel配置项中,plugins和presets均以数组的形式配置,执行时有先后顺序。
1.9 Babel工程管理方式
如果一个大型项目由多个独立的工程组成,该如何管理呢?
通常来说,有两种方式:
monorepo
monorepo指的是,该项目所有工程统一在一个仓库中,统一维护、发布。
目前React、Angular等均采用该方式。
multirepo
和monorepo相反,该项目的每个子工程独立运行,每个子工程相互独立,自由选择构建工具,独立发布。
二者对比如下:
Babel项目涉及的子工程很多,其采用了monorepo方式开发,并且沉淀出了自动化工具lerna,当然也有其他工具实现了monorepo。
Babel使用的lerna命令行工具中,
lerna bootstrap
命令负责统一安装依赖,lerna publish
命令负责统一发布工程内的子项目。Babel的大部分package(如babel-core、babel-parser等)的版本号是始终一致的,这也是monorepo项目的一个特点。
monorepo项目中,开发者和使用者可以快速地查看当前工具集的统一版本,无需深入每个package查看版本并理解各自的关联关系。
1.10 总结
本文我们从宏观层面了解了Babel的编译过程及其生态中各个模块的作用,能够初步理解Babel是怎样运行的。
其中涉及的实现原理,我们拆解到其他文章中。
The text was updated successfully, but these errors were encountered: