babel 是什么
Babel 是一个工具链,主要用于将采用 ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。
从字面意思看,从字面意思看,从字面意思看,babel 就是一个能将 高阶的 ES2015+ 的语法转化成低阶 ES5 语法的编译器。如果从这句话完成对 babel 的定性,那么就陷入误区。
babel 能干什么
- 将采用 ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 语法。
- 通过 Polyfill 方式在目标环境中添加缺失的特性。 babel 的作用才能真正揭示了 babel 是什么:translater + polyfill。
为什么需要 @babel/preset-env
负责语法转换层面的工作。比如,Class, ArrowFunction, async 等。
为什么需要 @babel/polyfill
负责API转换层面的工作。比如,Map, Set, Promise 等。
为什么需要 @babel/plugin-transform-runtime
复用 @babel/runtime/helpers 中的方法,避免代码冗余。@babel/plugin-transform-runtime 是锦上添花,不是雪中送炭。不使用 @babel/plugin-transform-runtime 也可以,但是不优雅。在不使用 @babel/plugin-transform-runtime 的情况下,每一个 js 文件都会声明自己的工具方法,例如为对象定义属性的方法 defineProperty 会地出现任何需要它的文件中。为什么不将 defineProperty 写在一个公共的地方以供所有需要它的文件复用呢?
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
@babel/plugin-transform-runtime 就能够解决这个问题。@babel/runtime/helpers 中包含大量的公共方法。
配置实践
必要的依赖
"dependencies": {
"@babel/polyfill": "^7.12.1"
},
"devDependencies": {
"@babel/cli": "^7.16.8",
"@babel/core": "^7.16.7",
"@babel/plugin-transform-runtime": "^7.16.8",
"@babel/preset-env": "^7.16.8",
"core-js": "^3.20.2"
}
@babel/preset-env 配置
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "10.8.0"
},
"corejs": 3, // core-js 的版本 2 或者 3
"useBuiltIns": "usage" // 只包含你所需要的 polyfill
}
]
],
useBuiltIns 选项需要说明,默认情况下,@babel/preset-env 会将当前环境看成是最低版本的环境。因此会将所有的特性都添加进来。下面就是@babel/polyfill全部的特性。
"use strict";
require("core-js/es6");
require("core-js/fn/array/includes");
require("core-js/fn/array/flat-map");
require("core-js/fn/string/pad-start");
require("core-js/fn/string/pad-end");
require("core-js/fn/string/trim-start");
require("core-js/fn/string/trim-end");
require("core-js/fn/symbol/async-iterator");
require("core-js/fn/object/get-own-property-descriptors");
require("core-js/fn/object/values");
require("core-js/fn/object/entries");
require("core-js/fn/promise/finally");
require("core-js/web");
require("regenerator-runtime/runtime");
从 @babel/polyfill 可以看出,@babel/polyfill 是依赖 core-js 和 regenerator-runtime。从 @babel/polyfill 的 package.json 文件也可以佐证这一点:package.json 的dependencies 选项包含 core-js 和 regenerator-runtime。
这样做虽然可行,但是没有必要。因为不同版本的环境会在不同程度上支持这些特性。最理想的情况是只需要引入缺失的特性就可以。所以需要告知 babel 当前的环境是什么,当前环境的版本是多少。因此,需要配置 tragets。
targets 选项需要特别说明,targets 指明当前的环境。或者是浏览器环境,或者是 NodeJS 环境。不仅要指定环境还要指定环境的版本。node 是环境,10.8.0 是版本。用户可以在 node.green 上查看当前版本的环境缺失的特性。环境的版本越低,缺失的特性越多,需要 @babel/polyfill 弥补的特性越多。