1. Babel简介
Babel 是一个 JavaScript 编译器
Babel 是一个工具链,主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。
1.1 babel能做的事情
1. 语法转换
2. 通过 Polyfill 方式在目标环境中添加缺失的特性 (通过 @babel/polyfill 模块, 在main.js中通过import方式进行引入即可)
3. 源码转换 (codemods)
1.2 初级配置
安装依赖
npm install --save-dev @babel/core @babel/cli @babel/preset-env
npm install --save @babel/polyfill
{
"presets": [
[
"@babel/env",
{
"targets": {
"edge": "17",
"firefox": "60",
"chrome": "67",
"safari": "11.1",
},
"useBuiltIns": "usage",
"corejs": "3.6.5",
}
]
]
}
useBuiltIns含义
“useBuiltIns”: false,
此时不对 polyfill 做操作。如果引入 @babel/polyfill,则无视配置的浏览器兼容,引入所有的 polyfill。
“useBuiltIns”: “entry”,
“corejs”: 2,
根据配置的浏览器兼容,引入浏览器不兼容的 polyfill。需要在入口文件手动添加 import ‘@babel/polyfill’,会自动根据 browserslist 替换成浏览器不兼容的所有 polyfill。
这里需要指定 core-js 的版本, 如果 “corejs”: 3,
则 import ‘@babel/polyfill’ 需要改成
import ‘core-js/stable’;
import ‘regenerator-runtime/runtime’;
“useBuiltIns”: “usage”,
“corejs”: 2,
usage 会根据配置的浏览器兼容,以及你代码中用到的 API 来进行 polyfill,实现了按需添加。
1.3 插件和预设(preset)
代码转换功能以插件的形式出现,插件是小型的 JavaScript 程序,用于指导 Babel 如何对代码进行转换。你甚至可以编写自己的插件将你所需要的任何代码转换功能应用到你的代码上。例如将 ES2015+ 语法转换为 ES5 语法,我们可以使用诸如 @babel/plugin-transform-arrow-functions 之类的官方插件:
npm install --save-dev @babel/plugin-transform-arrow-functions
./node_modules/.bin/babel src --out-dir lib --plugins=@babel/plugin-transform-arrow-functions
预设preset就是包含一系列插件的已有规则
因此我们可以通过指定预设来启用一组插件
就像插件一样,你也可以根据自己所需要的插件组合创建一个自己的 preset 并将其分享出去。J对于当前的用例而言,我们可以使用一个名称为 env 的 preset。
npm install --save-dev @babel/preset-env
./node_modules/.bin/babel src --out-dir lib --presets=@babel/env
使用nodejs api使用babel转译代码
const babel = require("@babel/core")
console.log(babel.transform("() => {console.log('hello world')}", {
plugins: ["@babel/plugin-transform-arrow-functions"] // 引用插件转译箭头函数
}).code)
插件的短名称
如果插件名称的前缀为 babel-plugin-,你还可以使用它的短名称:
{
"plugins": [
"myPlugin",
"babel-plugin-myPlugin" // 两个插件实际是同一个
]
}
插件顺序
插件的排列顺序很重要。
这意味着如果两个转换插件都将处理“程序(Program)”的某个代码片段,则将根据转换插件或 preset 的排列顺序依次执行。
插件在 Presets 前运行。
插件顺序从前往后排列。
Preset 顺序是颠倒的(从后往前)
插件参数
{
"plugins": [
[
"transform-async-to-module-method",
{
"module": "bluebird",
"method": "coroutine"
}
]
]
}
preset 的设置参数的工作原理完全相同:
{
"presets": [
[
"env",
{
"loose": true,
"modules": false
}
]
]
}
官网提供的预设
@babel/preset-env
@babel/preset-flow
@babel/preset-react
@babel/preset-typescript
Preset 的短名称
如果 preset 名称的前缀为 babel-preset-,你还可以使用它的短名称:
{
"presets": [
"myPreset",
"babel-preset-myPreset" // equivalent
]
}
1.4 配置
babel.config.json 的文件(需要 v7.8.0 或更高版本)
如果你使用的是 Babel 的旧版本,则文件名为 babel.config.js或者.babelrc
{
"presets": [
[
"@babel/env",
{
"targets": {
"edge": "17",
"firefox": "60",
"chrome": "67",
"safari": "11.1"
}
}
]
]
}
现在,名为 env 的 preset 只会为目标浏览器中没有的功能加载转换插件。语法都已经清楚了,接下来我们看看 polyfills 。
1.5 Polyfill
从 Babel 7.4.0 版本开始,这个软件包已经不建议使用了,建议直接包含 core-js/stable (用于模拟 ECMAScript 的功能)和 regenerator-runtime/runtime (需要使用转译后的生成器函数)
import "core-js/stable";
import "regenerator-runtime/runtime";
@babel/polyfill 模块包含 core-js 和一个自定义的 regenerator runtime 来模拟完整的 ES2015+ 环境。
这意味着你可以使用诸如 Promise 和 WeakMap 之类的新的内置组件、 Array.from 或 Object.assign 之类的静态方法、 Array.prototype.includes 之类的实例方法以及生成器函数(generator functions)(前提是你使用了 regenerator 插件)。为了添加这些功能,polyfill 将添加到全局范围(global scope)和类似 String 这样的原生原型(native prototypes)中。
对于软件库/工具的作者来说,这可能太多了。如果你不需要类似 Array.prototype.includes 的实例方法,可以使用 transform runtime 插件而不是对全局范围(global scope)造成污染的 @babel/polyfill。
更进一步,如你确切地指导你所需要的 polyfills 功能,你可以直接从 core-js 获取它们。
由于我们构建的是一个应用程序,因此我们只需安装 @babel/polyfill 即可:
npm install --save @babel/polyfill
注意,使用 --save 参数而不是 --save-dev,因为这是一个需要在你的源码之前运行的 polyfill。
幸运的是,我们所使用的 env preset 提供了一个 “useBuiltIns” 参数,当此参数设置为 “usage” 时,就会加载上面所提到的最后一个优化措施,也就是只包含你所需要的 polyfill。使用此新参数后,修改配置如下:
{
"presets": [
[
"@babel/env",
{
"targets": {
"edge": "17",
"firefox": "60",
"chrome": "67",
"safari": "11.1",
},
"useBuiltIns": "usage",
}
]
]
}
Babel 将检查你的所有代码,以便查找目标环境中缺失的功能,然后只把必须的 polyfill 包含进来。示例代码如下:
将被转换为(由于 Edge 17 没有 Promise.prototype.finally):
require("core-js/modules/es.promise.finally");
Promise.resolve().finally();
如果我们不使用 env preset 的 “useBuiltIns” 参数(即设置为 “usage”),那么我们必须在所有代码之前通过 require 加载一次完整的 polyfill。
1.6 总结
我们可以使用 @babel/cli 从终端运行 Babel,利用 @babel/polyfill 来模拟所有新的 JavaScript 功能,而 env preset 只对我们所使用的并且目标浏览器中缺失的功能进行代码转换和加载 polyfill。