Babel 手记

149 阅读4分钟
原文链接: juejin.im

Babel 是一个转译器,将 ES6+ 的语法转译成浏览器支持更好的 ES3/ES5 语法的代码。它的运行有三个阶段:

parse(解析)=> transforming(转码)=> printing(输出)

不经过配置的 Babel 实质上什么都不会做,解析你的代码,转码后输出相同的代码。只有通过增加 plugin(插件)来告诉 babel 应该如何转译代码。而我们熟悉的 preset(预设),只是一系列 plugin 的集合,免去了一个个的配置插件这个步骤。

Babel 的 git 仓库是一个 monorepo,其中包含 babel 的模块、helper,以及 plugin。

babel 模块

简要介绍 babel 中几个模块的作用。

babel-parser

babel 中使用的解析器。默认支持解析:

  1. 最新的 ECMAScript 语法
  2. 附加注释
  3. JSX, Flow, Typescript 语法
  4. 实验阶段的语法提案(支持至少达到 stage-0 阶段的 PR)

babel-core

babel 的核心模块,核心 api 都在这个模块里实现,比如,将字符串转译得到 AST 的方法 babel.transform,其它的 api 如 babel.transformFile, babel.transformFileSync, babel.transformFromAst,从这些 api 的命名大概能猜到它们的作用。

babel-cli

babel 的命令行工具,支持通过命令行对文件进行转译。

babel-node

会随 babel-cli 一起安装,安装后在命令行输入 babel-node,会启动一个 REPL ,还可以通过 babel-node 命令执行 js 文件,和 node 命令类似。

babel-register

引入该模块后,会给 noderequire 函数绑定一个钩子,当使用 node 的 require 方法时,会自动转译 .es6, .es, jsx, .mjs, .js 格式的文件(除了 node_modules 目录下的文件)。

babel-plugin-*

Babel 默认不会转译代码,需要通过配置插件来增加对语法的转译能力(注:可以通过配置 preset 来启用一系列插件)。 Babel 的插件分为两类,一类是 Transform Plugins,直译就是“转译插件”,这些插件会转译代码;另一类是 Syntax Plugins,直译就是“语法插件”,这类插件只做一件事,就是告诉 babel 要对特定类型的代码进行解析。 举例:一些需要被 polyfill 的代码,显然我们需要用到 Transform Plugins 这类插件,来把新的语法转译成兼容性更好的旧语法;而如果我们需要解析 vue 的单文件组件的语法,则首先需要用到 Syntax Plugins 这类插件来告诉 babel 如何解析这类语法。

注:Transform Plugins 会自动启用相应的 Syntax Plugins,不用特地去声明。其次,plugin 插件的引入和引入顺序是相关的,具体可以查看文档的对应章节

babel-preset-*

文章开始已经提到,preset(预设)只是一系列 plugin 的集合。Babel 的官方仓库中也提供了一些预设,如 babel-preset-env, babel-preset-stage-[0~3] 是对 ECMAScript 最新语法和 api 的支持, babel-preset-flow 是对 flow 语法检查工具的支持, babel-preset-react 是对 react 的支持,以及 babel-preset-typescript 是对 typescript 语法的支持。

babel-helper-*

helper 是一些供 babel 内部使用的工具库。我们常会使用 babel-plugin-external-helpers 插件,把一个文件中重复的 helper 代码(通常是 polyfill 的代码)移到文件顶部。

babel-polyfill

polyfill 直译过来就是“填充工具”,作用简单来说,就是给不支持某些 api 的旧浏览器打补丁,这样一来,开发的时候就可以始终使用新的语法、api,而不用考虑旧浏览器的兼容问题。 Babel 支持对部分新语法进行转译,如箭头函数,class, let, const 关键字等。但对于一些新的内置对象 Promise,全局对象的静态方法 Array.from,内置对象的示例方法 Array.prototype.includes,以及 generator 函数,这些浏览器支持度不全的语法,需要增加一些 polyfill,才能确保代码能在旧的浏览器中正常运行。

注:通常是完整引入,会对全局对象做修改,官方建议在开发应用时使用,会明显增加打包后文件的体积。

babel-runtime

与 babel-polyfill 的作用类似,官方建议在开发库或插件时使用。通常, babel-runtime 会和 babel-plugin-transform-runtime 插件一起使用,达到按需引入 polyfill 的效果。

其它

还有其它几个模块,如 babel-generator, babel-code-frame, babel-template, babel-traverse, babel-types,一般可能很少会和它们打交道,暂时先不讨论。