Babel 配置之 @babel/preset-env

1,530 阅读5分钟

概述

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 的参数项数量很多,但大部分我们都用不到。我们只需要重点掌握四个参数项即可:targetsuseBuiltInsmodulescorejs。如果要使用配置参数,就需要对 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 比较常见的一个作用就是帮助 Autoprefixerpostcss 判断是否要增加 CSS 前缀(例如 -webkit-)。我们的 Babel 也会用到 browserslist,当我们使用了 @babel/preset-env 这个预设,那么在 Babel 进行代码转换的过程中,就会读取 browserslist 的配置,从而按目标环境进行相应的转换。

如果我们的 @babel/preset-env 不设置任何参数,Babel 就会完全根据 browserslist 的配置来做语法转换。如果没有 browserslist ,那么 Babel 就会把所有 ES6 的语法转换成 ES5 版本。接下来我们来做一个小实验:

@babel/preset-env 无配置且不配置 browserslist

image.png

如图所示,我们定义了一个箭头函数,babel 最后会将其转换为 ES5 语法的普通函数。

配置 browserslist

image.png

image.png

我们可以看到,当我们制定了 chrome 60 版本以后,babel 并没有转换箭头函数,因为这个版本的 chrome 本身就支持箭头函数。

掌握了以上知识以后,我们可以正式开始讲 @babel/preset-env 的配置参数了。

@babel/preset-env 的 targets 参数

该参数项可以取值为字符串、字符串数组或对象,不设置的时候取默认值空对象{}。

该参数项的写法与 browserslist 是一样的,如果我们对 @babel/preset-envtargets 参数项进行了设置,那么就不使用 browserslist 的配置,而是使用 targets 的配置。如不设置 targets ,那么就使用 browserslist 的配置。

正常情况下,我们推荐使用 browserslist 的配置而很少单独配置 @babel/preset-envtargets

@babel/preset-env 的 useBuiltIns 参数

useBuiltIns 项取值可以是usageentryfalse。如果该项不进行设置,则取默认值 false

  • 设置成 false 的时候会把所有的 polyfill 都引入到代码中,整个体积会变得很大。
  • 设置成 entry 则是会根据目标环境引入所需的 polyfill
  • 设置成 usage 则是会根据目标环境和代码的实际使用来引入所需的 polyfill

⚠️使用方法与建议

使用 falseentry 时需要我们在项目入口处手动引入 polyfill,只能 import polyfill 一次,一般都是在入口文件。如果进行多次 import,会发生错误。

  • false 会引入所有polyfill,代码体积会变得很大,所以不建议使用。
  • entry 引入目标环境所需要的polyfill, 会有一些多余的文件,且需要在入口文件引入,使用起来比较麻烦。
  • usageBabel7.4 之前一直是试验性的,7.4 之后的版本稳定。usage 不需要手动引入 polyfill,如果在入口还是引入了文件,打包的时候就会有如下提示:

image.png

综上所述,使用 usage 会是一个比较好的选择。

@babel/preset-env 的 corejs 参数

该参数项的取值可以是 23,没有设置的时候取默认值为 2。这个参数只有 useBuiltIns 参数为 usage 或者 entry 时才会生效。

因为某些新的 API 只有 core-js@3 里才有,例如数组的 flat 方法,我们需要使用 core-js@3API 模块进行补齐,这个时候我们就把该项设置为 3

当我们将 corejs 配置为 2 或者使用默认配置时,需要安装 core-js@2 并引入,也可以安装并引入 @babel/polyfill(内部引入了 core-js2,又集成了 regenerator-runtime)。 如果我们的代码中使用了,生成器函数(Generator Functions)、asyncawait ,我们就需要引入 regenerator-runtime 模块。

Babel 7.4.0 开始,@babel/polyfill 软件包已被弃用, 所以还是建议使用 core-js@3。使用 core-js@3 时必须预先安装 core-js@3, 如果 useBuiltInsentry, 则在入口文件引入 core-js@3 ,如果 useBuiltInsusage,则不需要在入口文件引入。

配置实例

// babel 的配置文件
module.exports = {
  presets: [
    [
      "@babel/preset-env",
      {
        useBuiltIns: 'usage',
        corejs: 3
      }
    ]
  ],
  plugins: []
};

@babel/preset-env 的 modules 参数

这个参数项的取值可以是 amdumdsystemjscommonjscjsautofalse。在不设置的时候,取默认值 auto

在该参数项值是 auto 或不设置的时候,会发现我们转码前的代码里 import 都被转码成 require 了。

如果我们将参数项改成 false,那么就不会对 ES6 模块化进行更改,还是使用 import 引入模块。使用 ES6 模块化语法有什么好处呢?在使用 Webpack 一类的打包工具,可以进行静态分析,从而可以做 tree shaking 等优化措施。