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。
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 这个命令,适合安装在项目中。
原先 babel6 用的包是如 bable-cli 这类的,而升级 babel7 后,用的包都是以 @ 开头如 @babel/cli
。
@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
文件,配置如下:
{
"plugins": ["@babel/plugin-transform-arrow-functions"]
// 也可以指定插件的相对/绝对路径
// "plugins": ["./node_modules/@babel/plugin-transform-arrow-functions"]
}
执行 npm run compiler
即可执行编译箭头函数了,如果想将其它的 JS 新特性转成低版本,则需要使用其它对应的 plugin,但如果一个个配置的话会非常繁琐,因此 Babel 提供了预设。
4、预设 Presets
预设即 Babel 提供的一系列插件包,官方提供了以下四种预设:
- @babel/preset-env:智能预设,支持所有最新的 JS 特性。
- @babel/preset-react:React 预设。
- @babel/preset-typescript:TypeScript 预设。
- @babel/preset-flow:Flow 静态类型检查器预设。
二、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 };
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。