Babel 是一个转译器,将 ES6+ 的语法转译成浏览器支持更好的 ES3/ES5 语法的代码。它的运行有三个阶段:
parse(解析)=> transforming(转码)=> printing(输出)
不经过配置的 Babel 实质上什么都不会做,解析你的代码,转码后输出相同的代码。只有通过增加 plugin(插件)来告诉 babel 应该如何转译代码。而我们熟悉的 preset(预设),只是一系列 plugin 的集合,免去了一个个的配置插件这个步骤。
Babel 的 git 仓库是一个 monorepo,其中包含 babel 的模块、helper,以及 plugin。
babel 模块
简要介绍 babel 中几个模块的作用。
babel-parser
babel 中使用的解析器。默认支持解析:
- 最新的 ECMAScript 语法
- 附加注释
- JSX, Flow, Typescript 语法
- 实验阶段的语法提案(支持至少达到 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
引入该模块后,会给 node 的 require 函数绑定一个钩子,当使用 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,一般可能很少会和它们打交道,暂时先不讨论。