深入浅出 Babel 上篇:架构和原理 + 实战(1)

  • Babel 的处理流程

  • Babel 的架构

  • 访问者模式

  • 节点的遍历

  • 节点的上下文

  • 副作用的处理

  • 作用域的处理

  • 搞一个插件呗

  • 最后

  • 扩展

Babel 的处理流程

深入浅出 Babel 上篇:架构和原理 + 实战

深入浅出 Babel 上篇:架构和原理 + 实战

Babel 的处理流程

上图是 Babel 的处理流程, 如果读者学习过编译器原理,这个过程就相当亲切了.

首先从源码 解析(Parsing) 开始,解析包含了两个步骤:

1️⃣词法解析(Lexical Analysis): 词法解析器(Tokenizer)在这个阶段将字符串形式的代码转换为Tokens(令牌). Tokens 可以视作是一些语法片段组成的数组. 例如for (const item of items) {} 词法解析后的结果如下:

深入浅出 Babel 上篇:架构和原理 + 实战

深入浅出 Babel 上篇:架构和原理 + 实战

从上图可以看,每个 Token 中包含了语法片段、位置信息、以及一些类型信息. 这些信息有助于后续的语法分析。

2️⃣语法解析(Syntactic Analysis):这个阶段语法解析器(Parser)会把Tokens转换为抽象语法树(Abstract Syntax Tree,AST)

什么是AST?

它就是一棵’对象树’,用来表示代码的语法结构,例如console.log(‘hello world’)会解析成为:

深入浅出 Babel 上篇:架构和原理 + 实战

深入浅出 Babel 上篇:架构和原理 + 实战

Program、CallExpression、Identifier 这些都是节点的类型,每个节点都是一个有意义的语法单元。 这些节点类型定义了一些属性来描述节点的信息。

JavaScript的语法越来越复杂,而且 Babel 除了支持最新的JavaScript规范语法, 还支持 JSX、Flow、现在还有Typescript。想象一下 AST 的节点类型有多少,其实我们不需要去记住这么多类型、也记不住. 插件开发者会利用 ASTExplorer 来审查解析后的AST树, 非常强大。

AST 是 Babel 转译的核心数据结构,后续的操作都依赖于 AST

接着就是**转换(Transform)**了,转换阶段会对 AST 进行遍历,在这个过程中对节点进行增删查改。Babel 所有插件都是在这个阶段工作, 比如语法转换、代码压缩。

Javascript In Javascript Out, 最后阶段还是要把 AST 转换回字符串形式的Javascript,同时这个阶段还会生成Source Map。

Babel 的架构

我在《透过现象看本质: 常见的前端架构风格和案例》 提及 Babel 和 Webpack 为了适应复杂的定制需求和频繁的功能变化,都使用了微内核 的架构风格。也就是说它们的核心非常小,大部分功能都是通过插件扩展实现的

所以简单地了解一下 Babel 的架构和一些基本概念,对后续文章内容的理解, 以及Babel的使用还是有帮助的。

一图胜千言。仔细读过我文章的朋友会发现,我的风格就是能用图片说明的就不用文字、能用文字的就不用代码。虽然我的原创文章篇幅都很长,图片还是值得看看的

深入浅出 Babel 上篇:架构和原理 + 实战

深入浅出 Babel 上篇:架构和原理 + 实战

Babel 是一个 MonoRepo 项目, 不过组织非常清晰,下面就源码上我们能看到的模块进行一下分类, 配合上面的架构图让你对Babel有个大概的认识:

1️⃣ 核心:

@babel/core 这也是上面说的‘微内核’架构中的‘内核’。对于Babel来说,这个内核主要干这些事情:

  • 加载和处理配置(config)

  • 加载插件

  • 调用 Parser 进行语法解析,生成 AST

  • 调用 Traverser 遍历AST,并使用访问者模式应用’插件’对 AST 进行转换

  • 生成代码,包括SourceMap转换和源代码生成

2️⃣ 核心周边支撑

  • Parser(@babel/parser): 将源代码解析为 AST 就靠它了。 它已经内置支持很多语法. 例如 JSX、Typescript、Flow、以及最新的ECMAScript规范。目前为了执行效率,parser是不支持扩展的,由官方进行维护。如果你要支持自定义语法,可以 fork 它,不过这种场景非常少。

  • Traverser(@babel/traverse): 实现了访问者模式,对 AST 进行遍历,转换插件会通过它获取感兴趣的AST节点,对节点继续操作, 下文会详细介绍访问器模式。

  • Generator(@babel/generator): 将 AST 转换为源代码,支持 SourceMap

3️⃣ 插件

打开 Babel 的源代码,会发现有好几种类型的‘插件’。

  • 语法插件(@babel/plugin-syntax-*):上面说了 @babel/parser 已经支持了很多 JavaScript 语法特性,Parser也不支持扩展. 因此plugin-syntax-*实际上只是用于开启或者配置Parser的某个功能特性

  • 一般用户不需要关心这个,Transform 插件里面已经包含了相关的plugin-syntax-*插件了。用户也可以通过parserOpts配置项来直接配置 Parser

  • 转换插件: 用于对 AST 进行转换, 实现转换为ES5代码、压缩、功能增强等目的. Babel仓库将转换插件划分为两种(只是命名上的区别):

  • @babel/plugin-transform-*: 普通的转换插件

  • @babel/plugin-proposal-*: 还在’提议阶段’(非正式)的语言特性, 目前有这些

  • 预定义集合(@babel/presets-*): 插件集合或者分组,主要方便用户对插件进行管理和使用。比如preset-env含括所有的标准的最新特性; 再比如preset-react含括所有react相关的插件.

4️⃣ 插件开发辅助

  • @babel/template: 某些场景直接操作AST太麻烦,就比如我们直接操作DOM一样,所以Babel实现了这么一个简单的模板引擎,可以将字符串代码转换为AST。比如在生成一些辅助代码(helper)时会用到这个库

  • @babel/types: AST 节点构造器和断言. 插件开发时使用很频繁

  • @babel/helper-*: 一些辅助器,用于辅助插件开发,例如简化AST操作

  • @babel/helper: 辅

  • 20
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值