一、 功能概述
Babel 是一个 JavaScript compiler 。
Babel 是一个工具链,主要用于在当前和旧的浏览器或环境中,将 ECMAScript 2015+ 代码转换为 JavaScript 向后兼容版本的代码。主要功能:
- 转换语法
- Polyfill 目标环境中缺少的功能(通过如 core-js 的第三方 polyfill)
- 源代码转换(codemods)
// Babel 输入:ES2015 箭头函数
[1, 2, 3].map(n => n + 1);
// Babel 输出:ES5 等价语法
[1, 2, 3].map(function(n) {
return n + 1;
});
转换规则会体现为插件的形式,插件是小型 JavaScript 程序,它指示 Babel 如何进行代码转换,可以编写自己的插件,来应用任何转换规则
二、 插件 plugins
通过在 配置文件 中应用插件(或 预设),可以启用 Babel 的代码转换。
2.1 使用一个插件
- 插件在 npm 中,传入插件的名字,Babel 会检查它是否安装在 node_modules 中
{
"plugins": ["babel-plugin-myPlugin", "@babel/plugin-transform-runtime"]
}
- 指定插件的 相对/绝对 路径。
{
"plugins": ["./node_modules/asdf/plugin"]
}
2.2 插件排序
- 插件在预设之前运行。
- 插件排序是从第一个到最后一个。
- 预设顺序是颠倒的(最后一个到第一个)。
<!--先 transform-decorators-legacy 再 transform-class-properties-->
{
"plugins": ["transform-decorators-legacy", "transform-class-properties"]
}
<!--先 @babel/preset-react 再 @babel/preset-env-->
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
2.3 插件选项
插件和预设都可以通过将名称和选项对象包装在数组中来指定配置内的选项.
{
"plugins": [
[
"transform-async-to-module-method",
{
"module": "bluebird",
"method": "coroutine"
}
]
]
}
2.4 插件分类
- 转换类插件:转译代码
- 语法类插件:大多数语法可以通过 Babel 进行转译
注意事项
- 如果已经使用了相应的转换插件,则不需要指定语法插件,因为它会自动启用
- 如果转译还没有实现,或者没有默认的实现方式,可以使用
@babel/plugin-syntax-bigint
之类的插件来只允许 Babel 解析 特定类型的语法。
三、 预设 presets
Babel 预设可以作为 Babel 插件和配置 选项 的共享集。
3.1 官方预设
- @babel/preset-env 用于编译 ES2015+ 语法
- @babel/preset-typescript 用于 TypeScript
- @babel/preset-react 用于 React
- @babel/preset-flow 用于 Flow
3.2 使用预设
- 预设在 npm 中,传入插件的名字,Babel 会检查它是否安装在 node_modules 中
{
"presets": ["babel-preset-myPreset", "@babel/preset-env"]
}
- 指定预设的 相对/绝对 路径。
{
"presets": ["babel-preset-myPreset", "@babel/preset-env"]
}
3.3 预设排序
- 插件在预设之前运行。
- 预设顺序是颠倒的(最后一个到第一个)。
<!--c,b,然后 a-->
{
"presets": ["a", "b", "c"]
}
3.4 预设选项
插件和预设都可以通过将名称和选项对象包装在数组中来指定配置内的选项.
{
"presets": [
[
"@babel/preset-env",
{
"loose": true,
"modules": false
}
]
]
}
四、 配置文件
Babel 是可配置的!所有 Babel API 可选项 都可以配置。
4.1 babel.config.json
在项目的根目录(package.json 所在的位置)中,创建一个名为 babel.config.json 的文件
{
"presets": [...],
"plugins": [...]
}
4.2 babel.config.js
在项目的根目录(package.json 所在的位置)中,创建一个名为 babel.config 的文件
const presets = [ ... ];
const plugins = [ ... ];
if (process.env["ENV"] === "prod") {
plugins.push(...);
}
module.exports = { presets, plugins };
4.3 .babelrc.json
在项目中创建一个名为 .babelrc.json 的文件
{
"presets": [...],
"plugins": [...]
}
4.4 package.json
在 package.json 的 key babel 中指定
{
"name": "my-package",
"version": "1.0.0",
"babel": {
"presets": [ ... ],
"plugins": [ ... ],
}
}
4.5 配置文件类型选择
- 如果你的复杂配置有条件表达式或是在构建时计算的,JS 配置文件则非常方便。 然而,缺点是 JS 配置的静态可分析性较差, 因此对可缓存性、代码检测、IDE 自动完成等有负面影响。
- 由于 babel.config.json 和 .babelrc.json 是静态 JSON 文件, 因此它允许其他使用 Babel 的工具,如绑定器,安全地缓存 Babel 的结果, 这可能会带来巨大的构建性能优势。
- 建议尽可能使用 babel.config.json
五、 Webpack 配置
5.1 安装
yarn add babel-loader@8.2.5 @babel/core -D
5.2 webpack.config.js
<!--设置开发模式方便查看代码-->
const mode = "development";
//添加 babel 支持
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
rootMode: "upward",
}
}
},
- 如果工作目录还不是单体式仓库的根目录,需要启用 rootMode 选项
5.3 babel.config.json
{
"presets": [],
"plugins": []
}
六、使用插件
6.1 转换新语法
以 箭头函数 转换为例。
6.1.1 安装
yarn add @babel/plugin-transform-arrow-functions -D
6.1.2 babel.config.json
{
"plugins": [
["@babel/plugin-transform-arrow-functions", { "spec": true }]
]
}
6.1.3 打包
<!--main.boundle.js 部分内容-->
const arrowFunc = function arrowFunc() {
_newArrowCheck(this, _this);
console.log("arrowFunc");
}.bind(undefined);
6.2 polyfill 缺失的功能
6.2.1 安装
yarn add @babel/polyfill -D
6.2.2 webpack.config.js
entry: ["@babel/polyfill", "./src/main.js"],
6.2.3 打包
由于是在 webpack 打开的 entry 配置的 polyfill,所以是所有 polyfill 都存在。使用数组的 findLast 属性进行验证。
执行打包操作后,可以在 main.boundle.js
找到 findLast 的 polyfill 内容。
<!--main.boundle.js 部分内容-->
/***/ "./node_modules/core-js/modules/es.array.find-last.js":
/*!************************************************************!*\
!*** ./node_modules/core-js/modules/es.array.find-last.js ***!
\************************************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nvar $ = __webpack_require__(/*! ../internals/export */ \"./node_modules/core-js/internals/export.js\");\nvar $findLast = __webpack_require__(/*! ../internals/array-iteration-from-last */ \"./node_modules/core-js/internals/array-iteration-from-last.js\").findLast;\nvar addToUnscopables = __webpack_require__(/*! ../internals/add-to-unscopables */ \"./node_modules/core-js/internals/add-to-unscopables.js\");\n\n// `Array.prototype.findLast` method\n// https://github.com/tc39/proposal-array-find-from-last\n$({ target: 'Array', proto: true }, {\n findLast: function findLast(callbackfn /* , that = undefined */) {\n return $findLast(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);\n }\n});\n\naddToUnscopables('findLast');\n\n\n//# sourceURL=webpack:///./node_modules/core-js/modules/es.array.find-last.js?");
/***/ }),
七、使用预设
随着需要支持的功能越来愈多,需要安装和配置的 plugin 越来越多,可以使用 preset 来简化配置。@babel/preset-env 是一个智能预置,允许使用最新的 JavaScript,而不需要具体管理不同浏览器运行环境进行那些语法转换或者 polyfill。
7.1 安装
yarn add @babel/preset-env core-js@3.26.0 -D
7.2 babel.config.json
@babel/preset-env
已经包含了@babel/plugin-transform-arrow-functions
的功能,所以不需要在 plugins 中单独配置@babel/preset-env
内置 polyfill 功能,结合 core-js 实现,不在需要@babel/polyfill
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "entry",
"corejs": "3.22"
}
]
]
}
7.3 core-js 配置
import "core-js";
在项目中只能导入一次@babel/polyfill
中已经包含了core-js
,重复导入会报错- 建议创建入口文件,并使用导入语句
所以webpack需要删除 @babel/polyfill
相关配置
<!--webpack.config.js 部分代码-->
// entry: ["@babel/polyfill", "./src/main.js"],
entry:"./src/main.js",
并且在入口文件处导入 core-js
<!--main.js 部分代码-->
import "core-js";]
...
7.4 .browserslistrc 配置
仍然使用数组的 findLast 属性进行验证,该api的兼容性说明 Chrome 浏览器从 97 版本才开始支持
# 测试 Array.findLast() polyfill
# 进行polyfill
chrome >= 96
# 不进行polyfill
# chrome >= 97
进行打包,然后在 main.boundle.js
中搜索 es.array.find-last.js
/***/ "./node_modules/core-js/modules/es.array.find-last.js":
/*!************************************************************!*\
!*** ./node_modules/core-js/modules/es.array.find-last.js ***!
\************************************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nvar $ = __webpack_require__(/*! ../internals/export */ \"./node_modules/core-js/internals/export.js\");\nvar $findLast = __webpack_require__(/*! ../internals/array-iteration-from-last */ \"./node_modules/core-js/internals/array-iteration-from-last.js\").findLast;\nvar addToUnscopables = __webpack_require__(/*! ../internals/add-to-unscopables */ \"./node_modules/core-js/internals/add-to-unscopables.js\");\n\n// `Array.prototype.findLast` method\n// https://github.com/tc39/proposal-array-find-from-last\n$({ target: 'Array', proto: true }, {\n findLast: function findLast(callbackfn /* , that = undefined */) {\n return $findLast(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);\n }\n});\n\naddToUnscopables('findLast');\n\n\n//# sourceURL=webpack:///./node_modules/core-js/modules/es.array.find-last.js?");
/***/ }),
修改成 97 版本后,由于 Chrome 浏览器已支持,无需 polyfill,所以在重新打包后的 main.boundle.js
中没有上述代码。