深入理解 Babel - 微内核架构与 ECMAScript 标准化|得物技术

随着浏览器版本的持续更新,浏览器对JavaScript的支持越来越强大,Babel的重要性显得较低了。但Babel的设计思路、背后依赖的ECMAScript标准化思想仍然值得借鉴。

本文涉及的Babel版本主要是V7.16及以下,截至发文时,Babel最新发布的版本是V7.25.6,未出现大版本更新,近2年也进入了稳定迭代期,本文的分析思路基本适用目前的Babel设计。

一、Babel简介

Babel是什么

Babel是JavaScript转译器,通过Babel,开发者可以自由使用下一代ECMAScript 语法。高版本ECMAScript语法将被转译为低版本语法,以便顺利运行在各类环境,如低版本浏览器、低版本 Node.js 等。

Babel 是转译器,不是编译器。下面是转译和编译的区别:

编译,一般指将一种语言转换为另一种语法和抽象程度等都不同的语言,常见的比如 gcc 编译器。

转译,一般指将一种语言转换为不同版本或者抽象程度相同的语言,比如 Babel 可以把 ECMAScript 6 语法转译为 ECMAScript 5语法。

利用 Babel,开发者可以使用 ECMAScript 的各种新特性进行开发,同时花极少的精力关注浏览器或其他JS运行环境对新特性的支持。甚至,开发者可以根据自身需要,创造属于自己的 JavaScript 语法。

Babel在转译的时候,会对源码进行以下处理: 语法转译(Syntax)和添加API Polyfill。

01.jpg

  • 语法(Syntax)部分
    Babel 支持识别高版本语法,并通过插件将源码从高版本语法转译为低版本语法,如:

    • 箭头函数 () => {} 转为普通函数 function() {}。

    • const / let 转译为var

  • API Polyfill

有些运行时相关的 API,语法转译无法解决它们对低版本浏览器等环境的兼容性问题,因此 Babel 通过与 core-js 等工具的配合,实现 API 部分对目标环境(通常是低版本浏览器等)的兼容。

例如[1, 2, 3].include、Promise等 API,Babel 在处理时,如果目标环节可能不支持原生的 include / Promise 的话,Babel 会在转译结果中嵌入 include / Promise 的自定义实现。

有多种方式可以使用 Babel,如: 命令行(babel-cli、babel-node)、浏览器(babel-standalone)、API 调用(babel-core)、webpack loader(babel-loader)等。

转译过程

和多数转译器相同,Babel 运行的生命周期主要是 3 个阶段: 解析、转换、代码生成。

这个过程涉及抽象语法树:

抽象语法树(Abstract Syntax Tree,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。

AST 是树形对象,以结构化的形式表示编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。

02.jpg

源码字符串需要经转译器生成 AST,转译器有很多种,不同转译器,生成的AST对象格式细节可能有差异,但共同点为: 都是树形对象、该树形对象描述了节点特征、各节点之间的关系(兄弟、父子等)。

以下是 Babel 生命周期的三个过程:

  • 解析(Parsing): Code1 ==> 抽象语法树1
    解析过程包括 2 个环节: 词法解析、语法解析,最终生成抽象语法树。
    词法解析阶段,代码字符串被解析为 token 令牌数组,数组项是一个对象,包括: 代码字符碎片的值、位置、类型等信息。
    token 数组是平铺式的数组,没有嵌套的结构信息,它是为语法解析阶段做准备的。
    语法解析阶段,token 令牌数组被解析为结构化的抽放语法树对象(AST)。
    babel-parser 完成该阶段的主要功能。

03.jpg

  • 转换(Transformation): AST1 ==> AST2
    Babel 生成 AST 后,会对 AST 进行遍历,遍历过程中,各类插件对原 AST 对象进行增删改查等操作,AST 结构被修改。

04.jpg

  • 代码生成(Generation): AST2 ==> Code2
    Babel 将修改后的 AST 对象转目标代码字符串。
    babel-generator 完成该阶段的主要功能。

05.jpg

二、Babel微内核架构

微内核架构

Babel 采用微内核架构,其内核保留核心功能,其余功能利用外部工具和插件机制实现,也体现了"开放-封闭"的设计原则。

06.jpg

除了微内核设计架构,Babel 的模块设计也可以做如下分类:

07.jpg

转译模块

转译模块位于 Babel 微内核架构的"微内核"部分,该部分主要负责代码转译,也就是上面提到的"解析-转换-代码生成"过程。

该模块主要包括: babel-parser、babel-traverse、babel-generator。

  • babel-parser
    负责将代码字符串转为 AST 对象。
    有 2 点值得一提:

    • babel-parser 本身并不会对 AST 做转换操作,只是负责解析出 AST。AST 转换部分交由各类 plugins 和 presets 处理。

    • babel-parser 内置了对 ESNext/TypeScript/JSX/Flow 最新版本语法的支持,但很多默认是不开启的,目前没有开放插件机制扩展新语法。

  • babel-traverse
    在转译过程中,babel-traverse 负责遍历 AST 节点,并根据配置的 plugins/presets,在遍历过程中,对各个 AST 节点进行增删改查的操作。
    AST 是一个树形对象,遍历 AST 对象的过程也是一个深度优先遍历的过程。

  • babel-generator
    负责将 AST 节点,转为代码字符串,同时也可以生成 source-map。

插件模块

插件模块包括 plugins、presets。

  • plugins
    丰富的插件,帮助 Babel 成为一个非常成功的转译工具。
    对 AST 的遍历、转换是 Babel 转译的核心功能,但 Babel 本身并不参与该过程,将这些功能作为插件引入到运行时。
    具体来说,babel-core 作为核心工具,不提供对 AST 的修改逻辑,通过调用各类插件,实现对 AST 的修改。
    Babel的插件分为语法插件和转换插件。

    • 语法插件
      值得注意的是,babel-parser 负责将 JavaScript 代码解析出抽象语法树(AST),它支持全面识别 ESNext/TypeScript/JSX/Flow 等语法,目前由 Babel 团队开发维护,不支持插件化。
      Babel 插件生态中的语法插件,其功能就是作为"开关",配置是否开启 babel-parser 的某些语法转译功能。
      语法插件在 Babel 源码中,以 babel-plugin-syntax 开头。
      举个例子:

      • babel-plugin-syntax-decorators
        负责开启 babel-parser 对装饰器的语法支持。

      • babel-plugin-syntax-dynamic-import
        负责开启 babel-parser 对 import 语句的语法支持。

      • babel-plu

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值