Skip to main content

Babel 配置及其原理

Babel 是一个 JavaScript 编译器,主要用于将 ES6 以后的代码转为旧浏览器或环境中兼容的 JavaScript。主要功能有:

  • 转换语法
  • 通过 Polyfill 方式在目标环境中添加缺失的特性 (通过 @babel/polyfill 模块)
  • 源代码转换(codemods)
// Babel 输入:ES6 箭头函数
[1, 2, 3].map(n => n + 1);

// Babel 输出:ES5 等价语法
[1, 2, 3].map(function(n) {
return n + 1;
});

Babel 的原理:Babel 将高版本的 JS 语法解析成 AST 抽象语法树,再通过可插拔的插件机制,让每个插件对 AST 语法树做不同的处理,这样的插件集合组成了一个工具链,将 JS 代码编译成向后兼容的 JavaScript。

Babel 把字符串解析成 AST,是怎么进行词法/语法分析的?
  • input + tokenizer => tokens:首先对输入的源代码进行词法解析,根据最小有效语法单元,对字符串进行切割,获得 Token 流;
  • tokens + parser => AST:然后对 Token 流进行语法解析,会涉及到读取、暂存、回溯、暂存点销毁等操作,获得抽象语法树 AST;
  • AST + transformer => newAST:遍历抽象语法树的节点,进行分析和转换节点,从而获得新的抽象语法树;
  • newAST + codeGenerator => output:最后根据新的抽象语法树生成新的代码。

一、核心概念

1、@babel/core 核心库

Babel 的核心功能包含在 @babel/core 模块中。core 表示核心,不安装 @babel/core 则无法使用 babel 进行编译。

2、@babel/cli 命令行工具

babel 提供的命令行工具,主要是提供 babel 这个命令,适合安装在项目中。

与 babel-cli 的区别

原先 babel6 用的包是如 bable-cli 这类的,而升级 babel7 后,用的包都是以 @ 开头如 @babel/cli

关于 @babel/node

@babel/node 提供了 babel-node 命令,但 @babel/node 更适合全局安装,而非安装在项目中。

3、插件 Plugins

Babel 的插件分为两种:

  • 语法插件

这些插件只允许 Babel 解析(parse)特定类型的语法(而非转换),可以在 AST 转换时使用,以支持解析新语法:

import * as babel from '@babel/core'

const code = babel.transformFromAstSync(ast, {
// 支持可选链
plugins: ['@babel/plugin-proposal-optional-chaining'],
babelrc: false
}).code
  • 转换插件

转换插件会启用相应的语法插件,因此不需要同时指定这两种插件。

  • 插件如何使用?

如果插件发布在 npm 上,可以直接填写插件的名称,Babel 会自动检查它是否已经被安装在 node_modules 目录下,在项目目录下新建 .babelrc 文件,配置如下:

.babelrc
{
"plugins": ["@babel/plugin-transform-arrow-functions"]
// 也可以指定插件的相对/绝对路径
// "plugins": ["./node_modules/@babel/plugin-transform-arrow-functions"]
}

执行 npm run compiler 即可执行编译箭头函数了,如果想将其它的 JS 新特性转成低版本,则需要使用其它对应的 plugin,但如果一个个配置的话会非常繁琐,因此 Babel 提供了预设。

4、预设 Presets

预设即 Babel 提供的一系列插件包,官方提供了以下四种预设:

二、Babel 配置

1、安装所需的包

项目根目录下运行命令:

npm install --save-dev @babel/core @babel/cli @babel/preset-env

2、创建配置文件

项目根目录下创建一个命名为 babel.config.json 的配置文件,并复制以下内容:

{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"edge": "17",
"firefox": "60",
"chrome": "67",
"safari": "11.1"
},
"useBuiltIns": "usage",
"corejs": "3.6.5"
}
]
]
}

如果使用的是 Babel 的旧版本,则文件名为 babel.config.js

const presets = [
[
"@babel/preset-env",
{
targets: {
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1",
},
useBuiltIns: "usage",
corejs: "3.6.4",
},
],
];

module.exports = { presets };

点击查看 @babel/preset-env 配置项

3、编译到 lib 目录

运行以下命令将 src 目录下的所有代码编译到 lib 目录:

./node_modules/.bin/babel src --out-dir lib

可以将 ./node_modules/.bin/babel 命令缩短为 npx babel,例如:

npx babel src --out-dir lib

总之,使用 @babel/cli 从终端运行 Babel,而 env、preset 只对所使用且目标浏览器中缺失的功能进行代码转换和加载 polyfill。

三、如何写一个 Babel 插件

点击查看 Babel 插件手册

点击查看编译器底层实现