主要基于 Babel 7(更新于2018年08月)。
是什么?有什么用途?
是一个 Javascript 编译器。
Babel 是一个工具链,主要用于将 ECMAScript 2015+ 代码转换为当前版本和旧版浏览器或环境中的向后兼容版本的 JavaScript。包括但不限于:
- 转换语法。 如箭头函数、let 等 ES2015+ 语法,JSX 语法。
- 通过 Polyfill 支持新 API,如 Promise、Array.prototype.includes。(可以通过第三方 polyfill,例如 core-js)
- 源代码转换 (codemods) 。如:去除 Flow / TypeScript 代码中的类型注释。
相似的技术
关键概念 plugin / preset / polyfill
概念 | 作用 | 示例 |
---|---|---|
plugin | 负责转译特定的语法特性 | @babel/plugin-transform-arrow-functions |
preset | Plugin 的集合,简化多个语法的兼容配置 | @babel/preset-env @babel/preset-typescript @babel/preset-react |
polyfill | 兼容性代码,为旧环境提供现代 API 支持 | core-js |
三者关系与协同工作
- plugin 与 preset:plugin 是 Babel 的最小转译单元,而 preset 是 plugin 的集合。preset 会根据目标环境的配置决定包含哪些 plugin。
- preset 与 polyfill:
@babel/preset-env
等 preset 可以根据目标环境判断代码中是否需要 polyfill,并自动加载core-js
中的 polyfill,保证兼容性。 - 协同工作流程:当我们使用
@babel/preset-env
配置了targets
和useBuiltIns: "usage"
时,Babel 会通过插件转译不支持的语法,同时通过 polyfill 实现缺失的 API,使项目在目标环境中无缝运行。
介绍一个常见 preset:@babel/preset-env
@babel/preset-env
是一个“聪明”的预设(preset),它能让你使用最新的 JavaScript 语法而无需操心对目标环境所支持的语法设置相应的语法转换插件(以及可选的 polyfills)。
@babel/preset-env
不包含任何未进入 Stage 3 阶段的 JavaScript 语法提案,因为在 TC39 的流程中,未进入 Stage 3 阶段的提案是不会被任何浏览器所实现的。
三个关键参数:target
/ useBuiltIns
/ corejs
target
Describes the environments you support/target for your project.
简单讲,该参数决定了我们项目需要适配到的环境,比如需要适配的浏览器版本。不过官方推荐使用 .browserslistrc 配置。
useBuiltIns
: "usage" | "entry" | false, defaults to false
This option configures how
@babel/preset-env
handles polyfills.
这个参数决定了 preset-env 如何处理 polyfills。
选项值 | 含义 | 其他处理 |
---|---|---|
false | 不会引入 polyfills | 在入口文件处自行引入相关 polyfill: import 'core-js/stable'; import 'regenerator-runtime/runtime'; |
"usage" | babel 会根据用户代码的使用情况,并根据 targets 自行注入相关 polyfills。在项目的入口文件处不需要 import 对应的 polyfills 相关库。 | |
"entry" | 需要在项目的入口文件处 import 对应的 polyfills 相关库。babel 会根据当前 targets 描述,把需要的所有的 polyfills 全部引入到你的入口文件(注意是全部,不管你是否有用到高级的 API)。 |
如果担心在自己的项目中第三方包未引入对应的 polyfill,可以使用 "entry"。
corejs
string
or{ version: string, proposals: boolean }
, defaults to"2.0"
. Theversion
string can be any supportedcore-js
versions. For example,"3.33"
or"2.0"
.This option only has an effect when used alongside
useBuiltIns: usage
oruseBuiltIns: entry
, and ensures@babel/preset-env
injects the polyfills supported by yourcore-js
version.It is recommended to specify the minor version otherwise
"3"
will be interpreted as"3.0"
which may not include polyfills for the latest features.By default, only polyfills for stable ECMAScript features are injected: ...
用于指定 core-js 的版本,以及是否启用 proposals(支持提案,默认不开启,即只使用稳定版本的 ECMAScript 功能/特性)。
该设置项仅对于 useBuiltIns 为 "usage" | "entry" 时有效。
最常用的 polyfill:core-js
是什么?
是 JavaScript 标准库的 polyfill(垫片/补丁)。
如何使用
As of Babel 7.4.0, this package has been deprecated in favor of directly including
core-js/stable
(to polyfill ECMAScript features):
import "core-js/stable";
If you are compiling generators or async function to ES5, and you are using a version of
@babel/core
or@babel/plugin-transform-regenerator
older than7.18.0
, you must also load theregenerator runtime
package. It is automatically loaded when using@babel/preset-env
'suseBuiltIns: "usage"
option or@babel/plugin-transform-runtime
.出自 www.babeljs.cn/docs/babel-…
另外,core-js 的文档也有提及如何结合 Babel 使用。
从上面这段描述可以看出,结合 Babel 使用 core-js 的方式有这 3 种:
-
@babel/polyfill
- 从 Babel 7.4.0 开始,此软件包已被弃用。
- 取而代之的是直接引入
core-js/stable
。如果您正在将生成器或异步函数编译为 ES5,并且您使用的 @babel/core 或 @babel/plugin-transform-regenerator 版本早于 7.18.0,则还必须加载 regenerator runtime。需要在入口文件主动引入相关 polyfill:(❓core-js 不包含 regenerator 吗?)
import 'core-js/stable'; import 'regenerator-runtime/runtime';
-
通过 preset
@babel/preset-env
实现 core-js 的按需引入。- 需要将设置项 useBuiltIns 设为 "usage"(如果设为"entry"则表示直接引入整个 core-js),另外可以通过设置项 corejs 来设置使用的 core-js 版本。
- 需要注意,preset-env 的 polyfill 会污染全局环境。
-
通过 plugin
@babel/plugin-transform-runtime
实现 core-js 的按需引入。-
安装依赖:
-
开发环境依赖
@babel/plugin-transform-runtime
-
生产环境依赖
@babel/runtime
/@babel/runtime-corejs2
/@babel/runtime-corejs3
corejs
optionInstall command false
npm install --save @babel/runtime
2
npm install --save @babel/runtime-corejs2
3
npm install --save @babel/runtime-corejs3
-
-
简单介绍 @babel/plugin-transform-runtime
A plugin that enables the re-use of Babel's injected helper code to save on codesize.
该插件的出现就是复用 babel 注入的关联代码。
主要做了三件事:
- Automatically requires
@babel/runtime/regenerator
when you use generators/async functions (toggleable with theregenerator
option).- Can use
core-js
for helpers if necessary instead of assuming it will be polyfilled by the user (toggleable with thecorejs
option)- Automatically removes the inline Babel helpers and uses the module
@babel/runtime/helpers
instead (toggleable with thehelpers
option).
- 当您使用生成器/异步函数时自动引入
@babel/runtime/regenerator
(通过选项 regenerator 进行设置)。 (❓为什么 regenerator 没有包含在 core-js 里面?) - 如果需要,可以使用 core-js 作为辅助程序,而不是假设它会被用户填充(通过选项 corejs 进行设置)
- 自动删除内联 Babel 帮助程序并改用模块
@babel/runtime/helpers
(通过选项 helpers 进行设置)。
使用场景
@babel/preset-env
和 @babel/plugin-transform-runtime
二者都可以通过设置 corejs
选项来处理 polyfill,二者各有使用场景,在项目开发和类库开发的时候可以使用不同的配置。
不要同时为二者配置 core-js 的功能,以免产生复杂的不良后果。
场景一:项目开发
对于 @babel/preset-env,useBuiltIns 使用 "usage",尽量使用社区广泛使用的优质库以优化打包体积,不使用暂未进入规范的特性。对于 @babel/plugin-transform-runtime 只使用其移除内联复用的辅助函数的特性,减小打包体积。
// babel.config.json
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": {
"version": 3,
// 个人觉得默认情况下不推荐使用 proposals 功能,只使用最新规范中的特性。
"proposals": false
}
}
]
],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
// 默认值,即使如此依然需要安装 @babel/runtime 作为生产环境的依赖项。
"corejs": false
}
]
]
}
场景二:类库开发
类库开发尽量不使用污染全局环境的 polyfill,因此 @babel/preset-env 只发挥语法转换的功能,polyfill 由 @babel/plugin-transform-runtime 来处理,推荐使用 core-js@3,并且不使用未进入规范的特性。
// babel.config.json
{
"presets": [
["@babel/preset-env"]
],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": {
"version": 3,
"proposals": true
}, // 默认值为 false。设为 true 表示不需要添加支持 CommonJS 的代码,这可以减小构建产物体积。
"useESModules": true
}
]
]
}
以上示例中,选择了使用 core-js v3,并通过设置 proposals 为 true,选择了使用支持提案语法的功能。