[译]Babel文档之@babel/preset-env

9,416 阅读7分钟

Babel已成为前端工程化开发的必备工具链, 而@babel/preset-env(babel7.0 以后的插件与预设以@babel为前缀)是常用的一组预先设定的插件, Babel中文网暂未对该部分内容做翻译, 本文是对Babel英文官方文档中@babel/preset-env内容的翻译, 前端小xuo生英语渣渣水平有限, 欢迎指正与交流

@babel/preset-env

@babel/preset-env是一个智能的babel预设, 让你能使用最新的JavaScript语法, 它会帮你转换成代码的目标运行环境支持的语法, 提升你的开发效率并让打包后的代码体积更小

安装

使用npm

npm install --save-dev @babel/preset-env

使用yarn

yarn add @babel/preset-env --dev

运行机制

@babel/preset-env依赖了一些优秀的开源项目, 如browserslist, compat-table, electron-to-chromium...

我们利用这些数据源维护和增强Babel语法转换、语法实现, 来支持对应的目标环境的版本的语法、特征

注意@babel/preset-env不支持stage-x的插件

@babel/preset-env利用你指定的任何目标环境, 检查它们对应的插件并传给Babel

浏览器列表集合

对基于浏览器或者Electron的项目, 我们推荐使用一个.browserslistrc文件指定编译目标.如果你已经有了这个配置文件, 它将被很多前段工程化生态的工具利用到, 比如 autoprefixer, stylelint, eslint-plugin-compat...

如果没有配置targets或者ignoreBrowserslistConfig, @babel/preset-env将使用默认的Browserslist配置

如果你想支持市场份额大于0.25%而且忽略安全更新的浏览器如IE 10BlackBerry的语法转换和语法实现, 你可以采用如下的配置

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "entry"
      }
    ]
  ]
}

.browserlistrc

> 0.25%
not dead

或者你可以在package.json文件里配置

"browserslist": "> 0.25%, not dead"

配置项

如果你想获取更多关于配置项和预设的文档, 可参考preset options文档

targets

数据类型: string | Array<string> | { [string]: string }, 默认 {}

描述你的项目支持的目标环境

其可以是一个browserslist-compatible查询语句

{
  "targets": "> 0.25%, not dead"
}

或者是一个描述支持的最小的环境版本的对象

{
  "targets": {
    "chrome": "58",
    "ie": "11"
  }
}

环境如: chrome, opera, edge, firefox, safari, ie, ios, android, node, electron

注意, 如果不指定targets, @babel/prest-env会将所有的ECMAScript 2015+代码按照默认的配置去转换

我们不推荐这样使用, 因为这样没有利用到其支持特定浏览器的能力

{
  "presets": ["@babel/preset-env"]
}
targets.esmodules

数据类型: boolean

如果你代码运行的浏览器支持ES Modules(www.ecma-international.org/ecma-262/6.…), 当指定如下的配置, browers字段将被忽略, 你可以配合<script type="module"></script>专门为用户提供更小体积的代码文件(jakearchibald.com/2017/es-mod…)

请注意: 如果这样指定esmodules编译目标, browsers字段将被忽略

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "esmodules": true
        }
      }
    ]
  ]
}
targets.node

数据类型: string | "current" | true

如果你的编译针对当前的node版本, 你可以指定node配置项, 如果你指定为curren, 将等同于 "node": process.versions.node

targets.safari

数据类型: string | "tp"

如果你将针对Safari浏览器的技术预览版technology preview版本去编译, 可以指定"safari": "tp"

targets.browsers

数据类型: string | Array<string>

一个利用browserlist的查询选项, 如last 2 versions, > 5%, safari tp

注意, browsers的结果将被targets中冲突的项目覆写

注意: 这个配置项将在后期的版本里被移除, 利于只直接设置targets成一个查询语句

spec

数据类型: boolean, 默认为false

为一些允许的但是潜在的会比较慢的插件或者预设做配置

loose

数据类型: boolean, 默认为false

允许支持loose transformations的插件或者预设

modules

数据类型: "amd" | "umd" | "systemjs" | "commonjs" | "cjs" | "auto" | false, 默认为 "auto"

允转换ES6模块语法为其他的模块类型

设置为false将不会转换模块

注意cjscommonjs的一个别名

debug

数据类型: boolean, 默认为false

console.log输出编译目标或者使用的插件在plugin data version中指定的版本

include

数据类型: Array<string|RegExp>, 默认为[]

一个经常包含的插件的数组

合法的配置包括:

  • Babel plugins, @babel/plugin-transform-spread与不带前缀的plugin-transform-spread都支持
  • Built-ins(同时支持cores-js@2cores-js@3, 如es.map, es.set, 或者es.object.assign)

插件的名字可以用完整的或者部分的去指定, 或者使用正则表达式

可以接收的输入:

  • 全称(string): "es.math.sign"
  • 部分名称(string): "es.math.*"(解析为所有以es.math为前缀的插件)
  • 正则(Object): /^transform-.*$/ 或者 new RegExp("^transform-modules-.*")

注意以上正则表达式里的.相当于匹配所有的字符, 不仅仅是.字符. 而且注意正则表达式里.*glob*相反

如果一个原生的实现或者一节结合了不支持的特性加上支持的特性失效时, 这个选项对于debug会很有用

例如, Node 4支持原生的classes但是不支持spread, 如果super和参数spread一起使用, @babel/plugin-transform-classes需要被include, 不然的话就不可能被转译

注意: includeexclude选项仅在插件被预设包含时才会生效, 所以, 举个例子, 包含@babel/plugin-proposal-do-expressions, 或者排除@babel/plugin-proposal-function-bind将会报错, 如果要时候用预设里不包含的插件, 请直接将其添加至plugins

exclude

数据类型: Array<string|RegExp>, 默认为[]

一个记录不包含或者移除的插件的数组

可能的配置与include选项类似

这个选项相当于黑名单, 如果你不使用generators而且当配置useBuiltIns时不想包含regeneratorRuntime, 或者利用其它如fast-async的插件替换Babel's async-to-gen

useBuiltIns

数据类型: "usage" | "entry" | false, 默认false

这个选项配置了@babel/preset-env如何处理polyfill

usage或者entry选项被使用, @babel/preset-env将直接饮用cores-js模块相当于暴露imports或者requries, 这一位置core-js将被直接解析到文件本身而且需要可访问

因为@babel/polyfillBabel 7.4.0已被废弃, 我们推荐直接添加core-js和通过corejs选项设置版本

npm install core-js@3 --save

# or

npm install core-js@2 --save

useBuiltIns: 'entry'

注意: 你的整个app里只能使用一次import "core-jsimport "regenerator-runtime/runtime". 如果你正在使用@babel/polyfill, 其已包含了core-jsregenerator-runtime: 如果多次引入它或报错.多次引入这些包将导致全局的冲突和其它难易追踪的问题. 我们推荐创建一个只包含import声明的单入口文件

当需要根据不同的基于环境的入口需要引入不同的core-js时, 这个选项允许一个新的插件来替换import "core-js/stable"import "regenerator-runtime/runtime"声明(或者require("corejs")require("regenerator-runtime/runtime"))

In

import "core-js";

Out(基于不同的环境)

import "core-js/modules/es.string.pad-start";
import "core-js/modules/es.string.pad-end";

引入"core-js"加载了对于每一个可能的ECMAScript特性的语法填充, 如果你知道你只需要他们其中的某一部分呢, 当使用core-js@3@babel/preset-env, 能够对每一个core-js入口和其依赖的优化. 比如, 你看值需要填充数组方法和新的Math提案:

In

import "core-js/es/array";
import "core-js/proposals/math-extensions";

Out(基于不同的环境)

import "core-js/modules/es.array.unscopables.flat";
import "core-js/modules/es.array.unscopables.flat-map";
import "core-js/modules/esnext.math.clamp";
import "core-js/modules/esnext.math.deg-per-rad";
import "core-js/modules/esnext.math.degrees";
import "core-js/modules/esnext.math.fscale";
import "core-js/modules/esnext.math.rad-per-deg";
import "core-js/modules/esnext.math.radians";
import "core-js/modules/esnext.math.scale";

你可以阅读core-js的文档获取关于不同入口的信息

注意: 当使用core-js@2(使用corejs: 2配置项或者隐式使用), @babel/preset-env将也引入@babel/polyfill. 这种行为已被废弃, 因为不可能与@babel/polyfill使用不同的core-js版本

useBuiltIns: 'usage'

当文件里被使用时, 添加特定的引入来语法填充, 我们利用它, 一个打包的文件只会加载一次相同的语法填充

In

a.js

var a = new Promise();

b.js

var b = new Map();

Out(如果环境需要语法填充)

import "core-js/modules/es.promise";
var a = new Promise();
import "core-js/modules/es.map";
var b = new Map();

Out(如果环境支持该语法)

var a = new Promise();
var b = new Map();

useBuiltIns: false

不在每一个文件自动添加语法填充, 不转换import "core-js"import "@babel/polyfill"为单独的语法填充

corejs

数据结构: 2, 3 或者 { version: 2 | 3, proposals: boolean }, 默认为 2

这个选项只会在与useBuiltIns: usage或者useBuiltIns: entry一起使用时才会生效, 确保@babel/preset-env为你的core-js版本注入了正确的引入

默认只有稳定的 ECMAScript特性的语法填充才被注入, 你有三种方式去做语法填充:

  • 当使用useBuiltIns: "entry", 你可直接引入一个proposal polyfill: import "core-js/proposals/string-replace-all"