babel 基础
Babel
Babel 是什么?
Babel 是一个工具集,主要用于将 ES6 版本的 JS 代码转换为 ES5 等向后兼容的 JS 代码,从而可以运行在低版本浏览器或其它环境中。
因此,完全可以使用 ES6 编写程序,最后使用 Babel 转换为 ES5 这样就不用担心所在环境是否支持了。
Babel 配置:
Babel 的配置文件是 Babel 执行时默认在当前目录寻找的文件,主要有
.babelrc
{ "presets": ["es2015", "react"], "plugins": ["transform-decorators-legacy", "transform-class-properties"] }
.babelrc.js
.babel.config.js
// 对于 babel.config.js 和 .babel.js 它们的配置是一样的 // 通过 module.exports 输出配置项 module.exports = { "presets": ["es2015", "react"], "plugins": ["transform-decorators-legacy", "transform-class-properties"] }
.babel.config.json
.package.json
{ "name": "demo", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "babel": { "presets": ["es2015", "react"], "plugins": ["transform-decorators-legacy", "transform-class-properties"] } }
它们的配置项都是相同的,其实都是 plugins 和 presets,作用也是一样的,只需选择一种
除了将配置写在配置文件中,也可以写在构建工具的配置里,对于不同的构建工具,Babel 也提供了相应的配置,如 webpack 的 babel-loader 的配置项,本质和配置文件一样。
配置文件总结起来就是配置 plugins 和 presets 这两个数组,分别成为 插件数组 和 预设数组
除去 plugins 和 presets 这两个配置项,还有 minified、ignore等,但是平时基本用不到
推荐 后缀名 js 的配置文件因为可以用 js 做 逻辑处理
// 这里只是举个例子,实际项目中,我们可以传入环境变量等来做处理
var year = 2020;
var presets = [];
if (year > 2018) {
presets = ["@babel/env"];
} else {
presets = "presets": ["es2015", "es2016", "es2017"],
}
module.exports = {
"presets": presets,
"plugins": []
}
插件与预设:
plugin 代表插件,preset 代表预设,分别放在 plugins 和 presets下,每个预设或插件都是一个 npm 包
Babel 的 插件非常多,而所有的插件第必须先安装 npm 包到 node_modules 下才可使用
假如只配置插件数组,那么需要将插件都下载下来,那么 Babel 配置文件会非常臃肿
所以 presets 预设就是帮助解决这个问题的,预设是一组 Babel 插件的集合,如 babel-preset-es2015 就是所有处理 es2015 的二十多个 Babel 插件集合。另外,预设也可以是插件和其它预设的集合,所有的预设都需要先安装 npm 包 到 node_modules
plugin 与 preset 的短名称:
插件可以在配置文件里写短名称,如果插件的 npm 包名称前缀为 babel-plugin- , 那么可以省略前缀
如果 npm 包名称的前缀带有 npm 作用域 @ 如 @org/babel-plugin-xxx ,短名称可写 @org/xxx
目前 Babel7 的官方 npm 包里绝大部分插件已经升级为 @babel/plugin- 前缀的,这种情况的短名称比较特殊了,绝大部分可以像 babel-plugin- 那样省略 @babel/plugin- 。但 babel 官方并没有给出明确的说明,所以还是推荐用全称。
预设的短名称规则和插件的类似,预设 npm 包名称的前缀为 babel-preset- 或作用域 @xxx/babel-preset-xxx 的可以省略 babel-preset-
对于 Babel7 的官方 npm 包里绝大部分预设已经升级为 @babel/preset- 前缀的,这种情况的短名称比较特殊了,绝大部分可以像 babel-preset- 那样省略 @babel/preset- 。但 babel 官方并没有给出明确的说明,例如,@babel/preset-env 的短名称就是 @babel/env,所以还是推荐用全称。
执行顺序:
plugins 插件数组和 presets 预设数组是有顺序要求的,如果两个插件或预设都要处理一个代码块,那么会根据插件和预设的顺序来执行,规则如下:
- 插件比预设先执行
- 插件执行顺序是插件数组从前向后执行
- 预设执行顺序是预设数组从后向前执行
Babel 插件和预设的参数:
每个插件都是插件数组的成员项,每个预设都是预设数组的成员项,而要改写一个数组,数组的第一项是插件或预设的名称字符串,第二个是各对象,该对象由于设置第一项代表的插件或预设的参数,如:
// 给 @babel/preset-env 设置参数
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "entry"
}
]
]
}
预设和插件的选择:
目前来讲,可能会用到的预设可能只有四个:
- @babel/preset-env
- @babel/preset-flow
- @babel/preset-react
- @babel/preset-typescript
插件选择,目前较常用的插件只有 @babel/plugin-transform-runtime,很少见到其它,需要其它的插件时可以去官网找
Babel-polyfill:
在 Babel7 以后名称为 @babel/polyfill
polyfill 广义上讲为环境提供不支持的特性的一类文件或库
总的来说,Babel 官方的 polyfill 使用方法如下:
- 直接在 html 文件 引用 Babel 官方的 polyfill.js 脚本文件
- 在前端工程的入口文件里引入 polyfill.js
- 在前端工程的入口文件里引入 @babel/polyfill
- 在前端工程的入口文件里引入 core-js/stable 与 regenerator-runtime/runtime
- 在前端工程构建工具的配置文件入口引入 polyfill.js
- 在前端工程构建工具的配置文件入口引入 @babel/polyfill.js
- 在前端工程构建工具的配置文件入口引入 core-js/stable 与 regenerator-runtime/runtime
因为官方不在推荐使用 @babel/polyfill 包括官方的 polyfill.js
所以目前应该使用如下两个方法:
// 在 前端工程的 入口文件 引入 core-js/stable 和 regenerator-runtime/runtime
import "core-js/stable";
import "regenerator-runtime/runtime";
```javascript
// 在 前端工程构建工具的配置文件入口里引入 core-js/stable 和 regenerator-runtime/runtime
// 将 webpack.config.js 的 entry 项数组的前两项改为 core-js/stable 和 regenerator-runtime/runtime
const path = require('path');
module.exports = {
entry: ['core-js/stable', 'regenerator-runtime/runtime', './a.js'],
output: {
filename: 'b.js',
path: path.resolve(__dirname, '')
},
mode: 'development'
};
// 然后执行 npm run dev 打包
@babel/preset-env:
@babel/preset-env 的参数项,数量有十几个,但大部分要么用不到,要么将废弃,重点学的有 targets、useBuiltlns、modules、corejs。
对于 preset 当不需要对其设置参数时,只需将该 preset 名称放入 presets 中即可
module.exports = {
presets: ['@babel/env'], // @babel/env 为 @babel/preset-env 的缩写
plguins: []
}
如果需要对某个 preset 设置参数, 该 preset 就不能以字符串形式直接放在 presets 中,而是应该在包裹一层数组,数组第一项是该 preset 字符串,第二项是该 preset 的参数对象,如果该preset 没有参数需要设置,则数组第二项可以是空对象或不写第二项,一下方法是等价的:
module.exports = {
presets: ["@babel/env"],
plugins: []
}
```javascript
module.exports = {
presets: [["@babel/env", {}]],
plugins: []
}
```javascript
module.exports = {
presets: [["@babel/env"]],
plugins: []
}
```javascript
"browserslist": [
"> 1%",
"not ie <= 8"
]
// 即 目标环境是 市场份额大于 1% 的浏览器 且不考虑 IE8 及以下 IE 浏览器
// Browserslist叫做目标环境配置表,除了写在package.json里,也可以单独写在工程目录下.browserslistrc文件里。
// 用browserslist来指定代码最终要运行在哪些浏览器或node.js环境。Autoprefixer、postcss等就可以根据browserslist,来自动判断是否要增加CSS前缀(例如'-webkit-')。
// Babel也可以使用browserslist,如果使用了@babel/preset-env这个预设,此时Babel就会读取browserslist的配置。
// 如果 @babel/preset-env 不设任何参数。Babel 会 完全根据 browserslist 的配置做语法转换,如果没有 browserslist 那么 Babel 会 将所有 ES6 语法 转换为 ES5 版本
// 如果 Babel 没有配置任何预设或插件,那么 Babel 对转换的代码不做任何处理
参数项:
targets:
该参数项可以取值为字符串,字符串数组或对象,不设置的时候去默认值空对象 {}
写法同 browserslist 一样,如下:
module.exports = {
presets: [["@babel/env",{
targets: {
'chrome': "58",
"ie": "11"
}
}]],
plugins: []
}
// 如果 使用了 targets 参数,那么就不应该使用 browserslist ,反之,如果 targets 和 browserslist 都没有配置,那么默认将所有 ES6 语法 转换为 ES5
// 正常情况下 推荐使用 browserslist 的配置而非 targets
useBuiltIns:
useBuiltlns 项取值可以使 'usage'、'entry'、或 false 如果不配置,默认取 false
主要与 polyfill 行为有关,如果没有配置或取值为 false,polyfill 会全部引入最终的代码中去
取值为 entry 或 usage 时,会根据配置的目标环境找出需要的 polyfill 进行部分引入
useBuiltIns: 'entry'
module.exports = {
presets: [["@babel/env",{
useBuiltIns: 'entry'
}]],
plugins: []
}
// 会 根据输入的代码和目标浏览器 自动引入相应的补齐模块
// 需要在 入口文件 引入 polyfill
// 不会根据使用的 API 进行针对引入
// 使用 entry 时 只能 import polyfill 一次,多次 import 会报错
useBuiltIns: 'usage'
module.exports = {
presets: [["@babel/env", {
useBuiltIns: "usage"
}]],
plugins: []
}
// 会 根据输入代码好目标浏览器 自动引入相应补齐模块
// 不需要在 入口文件 引入 polyfill
// 根据使用的 API 进行针对引入
corejs:
参数项取值可以为 2 或 3,默认取值 2(还有一种对象 proposals 取值方法 ,但是实际用不到,可忽略)
只有 useBuiltIns 为 usage 或 entry 时生效
取默认值 2 时,Babel 转码使用的是 core-js@2 版本(即 core-js2.x.x)。因为某些新 API 只有 core-js@3 才有,如数组的 flat 方法,需要使用 core-js@3 的 API 模块进行补齐,此时将该项设为 3
在使用时,必须安装并引入 core-js 文件,值为 2 引入 @2 版本,值为 3 引入 @3 版本,否则会报错
modules:
可 取值 amd、umd、systemjs、commonjs、cjs、auto、false
默认取值 auto
用于设置是否将 ES6 模块语法转为 其它模块语法
常见的模块语法如下:
- ES6 的模块语法 import 与 export
- commonjs 模块语法 require 与 module.exports
值为 auto 或 不设置, import 会被转为 require
@babel/runtime
集成了所有语法转换会用到的辅助函数
{
"presets": [
"@babel/env"
],
"plugins": [
"@babel/plugin-transform-runtime"
]
}
具有三大作用:
- 会自动移出语法转换后内联的辅助函数,改为使用 @babel/runtime/helpers 里的辅助函数替代,减少了手动引入的麻烦
- 当代码使用了 core-js 的 API 自动引入 @babel/runtime-corejs3/core-js-stable/,以此代替全局引入的 core-js/stable
- 当代码使用了 Generator/async 函数,自动引入 @babel/runtime/regenerator 以此代替全局引入的 regenerator-runtime/runtime
作用 2 、3其实是在做 API 转换,对内置对象重命名,防止污染全局环境
{
"plugins": [
"@babel/plugin-transform-runtime"
]
}
// 是上方的默认值
{
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"helpers": true, // 是否自动引入辅助函数包。取值为 布尔值 默认为 true
"corejs": false, // 是否做 API 转换以避免污染全局环境 取 false 2 3
// 一般取 false 即 不对 Promise 这类 API 进行 转换
"regenerator": true,// 是否做 API 转换以避免污染全局环境 取布尔值
"useESModules": false, // 是否使用 ES6 模块化语法 取值 布尔值, 默认 false
// 在用 webpack 等打包工具时 设 true 以便静态分析
"absoluteRuntime": false, // 用于自定义
// @babel/plugin-transform-runtime 引入 @babel/runtime/ 模块的路径规则
// 取值 布尔值 或 字符串,没有特殊需求,不做修改 保持默认 false 即可
"version": "7.0.0-beta.0"
}
]
]
}