作者: 多巴胺
一、Babel 是什么
Babel 是一个可以将 使用ES2015+语法的代码 编译成 向后兼容 的代码的工具。当我们使用 EcmaScript 较高版本的 Javascript 语法特性的时候,将所写代码转换成兼容 ES5 的代码,目的支持尽可能多的平台。对于转换的规则,主要有分为以下两类:
- Sytanx类型。例如箭头函数、const/let 等语法特性,babel 可以通过各种插件实现兼容。
- 运行时api。例如数组的静态方法Array.from()、实例方法 arr.includes() 等,需要引入 corejs 作为 polyfill(垫片),从而能够在运行时提供支持。
二、功能模块构成
- 核心库——@babel/core
@babel/core 模块是一个可以完成代码字符串转换的库,babel所有的插件都是通过核心库来进行开发和加载的,如下是官方给的使用示例:
const babel = require("@babel/core");
babel.transform("code", optionsObject);
- 命令行工具——@babel/cli
当我们使用核心库的时候,一般不直接再代码中调用@babel/core提供的api,而是使用bable提供的命令行工具来进行源代码的转换。一般我们在使用的时候,将其作为 package.json 文件的一个 scripts 脚本进行配置,用于对指定文件夹的 js 语言做转换。例如以下示例,当我们运行 npm run babel,即可将根目录的 src 目录下所有的 js 文件进行转换,完成后放置于根目录 dist 下。
"scripts": {
"babel": "babel src --out-dir dist"
},
- 实际担任代码转化的角色——形形色色的 Plugin
babel 的语法转换功能依赖于各种插件。比如当我们使用箭头函数转换的插件 @babel/plugin-transform-arrow-functions ,当我们配置此插件后,源代码中的箭头函数将会被转换成普通的 Javascript 函数。
// 源代码
const print = (a) => console.log(a)
// 目标代码
var print = function print(a) {
return console.log(a);
};
- 插件集合——Presets
顾名思义,preset(预装置)就是多个插件的集合。例如,当我们的开发场景中需要使用箭头函数和可选操作符,那么我们可以将 @babel/plugin-transform-arrow-functions 和 @babel/plugin-proposal-optional-chaining 进行组合形成一个preset,当我们再次遇到需要使用箭头函数和可选操作符的转换场景的时候,直接使用此 preset,不必要在单个配置 Plugin。
官方提供了四个Presets,其中 @babel/preset-env 是我们常用的 preset,它提供了最新的 Javascript 语法转换,使用它,可以做到 Makes your life easier!
- 配置文件——推荐以 js 的形式
上文的介绍中,有很多的具体配置,那我们在什么地方进行 Plugin/Presets 的配置呢?官方给了多个文件类型和多个不同的文件,此处推荐使用 babel.config.js——即在根目录下创建 babel.config.js 并在其中导出 presets 和 plugins 对象。
当我们使用 Javascript 进行配置的时候,拥有更多的控制能力。可以以代码的方式控制在不同目标环境下应用不同的语法转换规则。
// 根目录下的 babel.config.js 文件中的内容
const plugins = [
'@babel/plugin-transform-arrow-functions',
'@babel/plugin-proposal-optional-chaining'
]
const presets = [
['@babel/env', {
useBuiltIns: 'usage',
corejs: 3
}]
]
module.exports = { plugins, presets }
三、Babel 的具体配置规则
在使用 babel 之前,我们首先安装 @babel/core, @babel/cli,命令如下:
npm install --save-dev @babel/cli @babel/core
在你项目的编译脚本中,添加如下脚本配置:
"scripts": {
"babel": "babel src --out-dir dist"
},
1. 仅做 Syntax 转换
当我们仅仅只想尝试某一个新的 Javascript 语法特性的时候,可以直接安装对应语法特性的 Plugin,例如当我们使用可选操作符 ( ?. ) 的时候,我们就可以安装 @babel/plugin-proposal-optional-chaining。
npm install --save-dev @babel/plugin-proposal-optional-chaining
之后,再更目录下创建 .babel.js 文件,写入此 Plugin 的配置并导出。
const plugins = [
'@babel/plugin-transform-arrow-functions',
]
module.exports = { plugins }
那么,我们尝试使用会发现,转换成功了。
// 源代码
const baz = obj?.foo?.bar?.baz;
// 转换后
var baz = obj === null || obj === void 0 ? void 0 : (_obj$foo = obj.foo) === null || _obj$foo === void 0 ? void 0 : (_obj$foo$bar = _obj$foo.bar) === null || _obj$foo$bar === void 0 ? void 0 : _obj$foo$bar.baz;
2. 推荐用法
为了尽量少的关心插件,我们可以使用官方提供的 @babel/preset-env。当我们配置此 Preset 时,让 babel 同时支持 Syntax 层面和 built-ins 层面的转化。为了支持 built-ins 转换,我们需要添加 useBuiltIns 的配置,具体步骤如下:
// 安装 @babel/preset-env
npm install --save-dev @babel/preset-env
// 安装 @core-js@3
// 由于 built-in 是运行时环境的依赖,所以要使用 --save
npm install --save core-js@3
// .babel.js 配置
const presets = [
['@babel/env', {
// 此配置项的值可以配置为 entry/usage
// entry: 注入目标环境不支持的所有 built-in 类型语法
// usage: 注入目标环境不支持的所有被用到的 built-in 类型语法
useBuiltIns: 'usage',
// built-in 需要 corejs 的支持。corejs3 支持对象的实例方法
corejs: 3
}]
]
module.exports = { presets }
3. @babel/plugin-transform-runtime
使用此插件的原因主要有两个:
- 默认情况下,babel 再做 built-in 类型的转换时,会在源代码每个文件里面引入 core-js 的 helper 函数,有时这是没有必要的。当使用 @babel/plugin-transform-runtime 时,所有的 helpers 都只会引 @babel/runtime。
- 此插件可以提供一个运行的沙箱环境。如果直接使用 core-js,那对于 Promise、Set 等对象,都会污染全局作用域。如果你现在开发的是一个工具包,你使用了 core-js 提供了 Promise、Set 的语法转换。当别人在他的项目里引入了你的工具包,恰恰他的项目中已经实现了 Promise、Set 等函数,这就会导致复杂的冲突问题。
配置如下所示:
// 安装 @babel/plugin-transform-runtime
npm install --save-dev @babel/plugin-transform-runtime
// 安装生产环境依赖
// 此处和是否使用 core-js 及 core-js 版本有关
// corejs: false
npm install --save @babel/runtime
// corejs: 3 以下配置示例中的 corejs 版本
npm install --save @babel/runtime-corejs3
// corejs: 2
npm install --save @babel/runtime-corejs2
// .babel.js 配置详情
// 这是在 nodejs 配置中推荐的使用方式
const plugins = [
['@babel/plugin-transform-runtime', {
corejs: 3
}]
]
// 此处需要注意,当我们使用了 @babel/runtime-corejs2,原先的 corejs@3 便不需要使用了
const presets = [
['@babel/env']
]
module.exports = { plugins, presets }
网友评论