概述
在 Babel6 时代,这个预设名字是 babel-preset-env,在 Babel7 之后,改成 @babel/preset-env。@babel/preset-env 是 Babel 中最重要的一个 preset,它包含所有稳定的转码插件,还可以根据我们设定的目标环境进行针对性转码。不夸张的说,仅仅需要它就可以完成现代 JS 工程所需要的所有代码转换。
使用方法
安装依赖
npm install --save-dev @babel/preset-env
设置 presets
// babel.config.js 文件
module.exports = {
presets: ["@babel/preset-env"], // 也可以写成 @babel/env
plugins: []
}
配置参数
@babel/preset-env 的参数项数量很多,但大部分我们都用不到。我们只需要重点掌握四个参数项即可:targets、useBuiltIns、modules 和 corejs。如果要使用配置参数,就需要对 babel.config.js 做一些简单的修改:
// babel.config.js 文件
module.exports = {
presets: [
[ // 将原来的 @babel/preset-env 字符串改成数组
"@babel/preset-env",
{ // @babel/preset-env 的配置对象
...
}
]
],
plugins: []
}
在开始讲具体配置项的作用之前,我们先说说 browserslist(目标环境配置表) ,具体 demo 如下:
"browserslist": [
"> 1%",
"not ie <= 8"
]
上面配置的含义是:目标环境是市场份额大于 1% 的浏览器并且不考虑 IE8 以下的浏览器。
browserslist 可以写在 package.json 中,也可以单独写在工程目录下的 .browserslistrc 文件里。我们可以用 browserslist 来指定代码最重要运行在那些浏览器或者 Node.js 环境。
browserslist 比较常见的一个作用就是帮助 Autoprefixer、postcss 判断是否要增加 CSS 前缀(例如 -webkit-)。我们的 Babel 也会用到 browserslist,当我们使用了 @babel/preset-env 这个预设,那么在 Babel 进行代码转换的过程中,就会读取 browserslist 的配置,从而按目标环境进行相应的转换。
如果我们的 @babel/preset-env 不设置任何参数,Babel 就会完全根据 browserslist 的配置来做语法转换。如果没有 browserslist ,那么 Babel 就会把所有 ES6 的语法转换成 ES5 版本。接下来我们来做一个小实验:
@babel/preset-env 无配置且不配置 browserslist
如图所示,我们定义了一个箭头函数,babel 最后会将其转换为 ES5 语法的普通函数。
配置 browserslist
我们可以看到,当我们制定了 chrome 60 版本以后,babel 并没有转换箭头函数,因为这个版本的 chrome 本身就支持箭头函数。
掌握了以上知识以后,我们可以正式开始讲 @babel/preset-env 的配置参数了。
@babel/preset-env 的 targets 参数
该参数项可以取值为字符串、字符串数组或对象,不设置的时候取默认值空对象{}。
该参数项的写法与 browserslist 是一样的,如果我们对 @babel/preset-env 的 targets 参数项进行了设置,那么就不使用 browserslist 的配置,而是使用 targets 的配置。如不设置 targets ,那么就使用 browserslist 的配置。
正常情况下,我们推荐使用 browserslist 的配置而很少单独配置 @babel/preset-env 的 targets。
@babel/preset-env 的 useBuiltIns 参数
useBuiltIns 项取值可以是usage、 entry 或 false。如果该项不进行设置,则取默认值 false。
- 设置成
false的时候会把所有的polyfill都引入到代码中,整个体积会变得很大。 - 设置成
entry则是会根据目标环境引入所需的polyfill; - 设置成
usage则是会根据目标环境和代码的实际使用来引入所需的polyfill。
⚠️使用方法与建议:
使用 false 和 entry 时需要我们在项目入口处手动引入 polyfill,只能 import polyfill 一次,一般都是在入口文件。如果进行多次 import,会发生错误。
false会引入所有polyfill,代码体积会变得很大,所以不建议使用。entry引入目标环境所需要的polyfill, 会有一些多余的文件,且需要在入口文件引入,使用起来比较麻烦。usage在Babel7.4之前一直是试验性的,7.4之后的版本稳定。usage不需要手动引入polyfill,如果在入口还是引入了文件,打包的时候就会有如下提示:
综上所述,使用 usage 会是一个比较好的选择。
@babel/preset-env 的 corejs 参数
该参数项的取值可以是 2 或 3,没有设置的时候取默认值为 2。这个参数只有 useBuiltIns 参数为 usage 或者 entry 时才会生效。
因为某些新的 API 只有 core-js@3 里才有,例如数组的 flat 方法,我们需要使用 core-js@3 的 API 模块进行补齐,这个时候我们就把该项设置为 3。
当我们将 corejs 配置为 2 或者使用默认配置时,需要安装 core-js@2 并引入,也可以安装并引入 @babel/polyfill(内部引入了 core-js2,又集成了 regenerator-runtime)。 如果我们的代码中使用了,生成器函数(Generator Functions)、async、await ,我们就需要引入 regenerator-runtime 模块。
从 Babel 7.4.0 开始,@babel/polyfill 软件包已被弃用, 所以还是建议使用 core-js@3。使用 core-js@3 时必须预先安装 core-js@3, 如果 useBuiltIns 是 entry, 则在入口文件引入 core-js@3 ,如果 useBuiltIns 是 usage,则不需要在入口文件引入。
配置实例:
// babel 的配置文件
module.exports = {
presets: [
[
"@babel/preset-env",
{
useBuiltIns: 'usage',
corejs: 3
}
]
],
plugins: []
};
@babel/preset-env 的 modules 参数
这个参数项的取值可以是 amd、umd、systemjs、commonjs、cjs、auto、false。在不设置的时候,取默认值 auto 。
在该参数项值是 auto 或不设置的时候,会发现我们转码前的代码里 import 都被转码成 require 了。
如果我们将参数项改成 false,那么就不会对 ES6 模块化进行更改,还是使用 import 引入模块。使用 ES6 模块化语法有什么好处呢?在使用 Webpack 一类的打包工具,可以进行静态分析,从而可以做 tree shaking 等优化措施。