关于babel:Babel-的原理

6次阅读

共计 2658 个字符,预计需要花费 7 分钟才能阅读完成。

残缺高频题库仓库地址:https://github.com/hzfe/aweso…

残缺高频题库浏览地址:https://febook.hzfe.org/

相干问题

  • Babel 是什么
  • Babel 有什么用
  • 压缩代码如何实现

答复关键点

JS 编译器 AST 插件零碎

Babel 是 JavaScript 编译器:他能让开发者在开发过程中,间接应用各类方言(如 TS、Flow、JSX)或新的语法个性,而不须要思考运行环境,因为 Babel 能够做到按需转换为低版本反对的代码;Babel 外部原理是将 JS 代码转换为 AST,对 AST 利用各种插件进行解决,最终输入编译后的 JS 代码。

知识点深刻

1. AST 形象语法树

简略定义:以树的模式来体现编程语言的语法结构。

利用在线 playground 调试,能够对 AST 有个直观感触:生成的树有多个节点,节点有不同的类型,不同类型节点有不同的属性。

const custom = "HZFE";

AST 是源代码的高效示意,能便捷的示意大多数编程语言的构造。实用于做代码剖析或转换等需要。之所以用树来进行剖析或转换,是因为树能使得程序中的每一节点恰好被拜访一次(前序或后续遍历)。

常见应用场景:代码压缩混同性能能够借助 AST 来实现:剖析 AST,基于各种规定进行优化(如 IF 语句优化;移除不可拜访代码;移除 debugger 等),从而生成更小的 AST 树,最终输入精简的代码后果。

2. Babel 编译流程

三大步骤

  1. 解析阶段:Babel 默认应用 @babel/parser 将代码转换为 AST。解析个别分为两个阶段:词法剖析和语法分析。
  • 词法剖析 :对输出的字符序列做标记化(tokenization) 操作。
  • 语法分析:解决标记与标记之间的关系,最终造成一颗残缺的 AST 构造。
  1. 转换阶段:Babel 应用 @babel/traverse 提供的办法对 AST 进行深度优先遍历,调用插件对关注节点的处理函数,按需对 AST 节点进行增删改操作。
  2. 生成阶段:Babel 默认应用 @babel/generator 将上一阶段解决后的 AST 转换为代码字符串。

3. Babel 插件零碎

Babel 的外围模块 @babel/core,@babel/parser,@babel/traverse 和 @babel/generator 提供了残缺的编译流程。而具体的转换逻辑须要插件来实现。

在应用 Babel 时,咱们可通过配置文件指定 plugin 和 preset。而 preset 能够是 plugin 和 preset 以及其余配置的汇合。Babel 会递归读取 preset,最终获取一个大的 plugins 数组,用于后续应用。

常见 presets

  • @babel/preset-env
  • @babel/preset-typescript
  • @babel/preset-react
  • @babel/preset-flow

最常见的 @babel/preset-env 预设,蕴含了一组最新浏览器已反对的 ES 语法个性,并且能够通过配置指标运行环境范畴,主动按需引入插件。

编写 Babel 插件

Babel 插件的写法是借助 访问者模式(Visitor Pattern)对关注的节点定义处理函数。参考一个简略 Babel 插件例子:

module.exports = function () {
  return {pre() {},
    // 在 visitor 下挂载各种感兴趣的节点类型的监听办法
    visitor: {
      /**
       * 对 Identify 类型的节点进行解决
       * @param {NodePath} path
       */
      Identifier(path) {path.node.name = path.node.name.toUpperCase();
      },
    },
    post() {},
  };
};

应用该 Babel 插件的成果如下:

// input

// index.js
function hzfe() {}

// .babelrc
{"plugins": ["babel-plugin-yourpluginname"]
}

``````
// output
function HZFE() {}

深刻 Babel 转换阶段

在转换阶段,Babel 的相干办法会取得一个插件数组变量,用于后续的操作。插件构造可参考以下接口。

interface Plugin {
  key: string | undefined | null;
  post: Function | void;
  pre: Function | void;
  visitor: Object;
  parserOverride: Function | void;
  generatorOverride: Function | void;
  // ...
}

转换阶段,Babel 会按以下程序执行。具体逻辑可查看源码:

  1. 执行所有插件的 pre 办法。
  2. 按需执行 visitor 中的办法。
  3. 执行所有插件的 post 办法。

一般来说,写 Babel 插件次要应用到的是 visitor 对象,这个 visitor 对象中会书写对于关注的 AST 节点的解决逻辑。而下面执行程序中的第二步所指的 visitor 对象,是整合自各插件的 visitor,最终造成一个大的 visitor 对象,大抵的数据结构可参考以下接口:

// 书写插件时的 visitor 构造
interface VisitorInPlugin {[ASTNodeTypeName: string]:
    | Function
    | {
        enter?: Function;
        exit?: Function;
      };
}

// babel 最终整合的 visitor 构造
interface VisitorInTransform {[ASTNodeTypeName: string]: {
    // 不同插件对雷同节点的解决会合并为数组
    enter?: Function[];
    exit?: Function[];};
}

在对 AST 进行 深度优先遍历 的过程中,会创立 TraversalContext 对象来把控对 NodePath 节点的拜访,拜访时调用对节点所定义的解决办法,从而实现按需执行 visitor 中的办法。具体实现请看 babel-traverse 中的源码。

参考资料

  1. AST
  2. Babel-handbook
  3. estree
  4. 访问者模式
正文完
 0