@babel/preset-env

@babel/preset-envopen in new window是一个灵活的预设,你可以无需管理目标环境需要的语法转换或浏览器polyfill,就可以使用最新的 JavaScript。这将让你的生活更简单,也会让 JavaScript 打包文件更小。

安装

# with npm
npm install --save-dev @babel/preset-env
1
2
# with yarn
yarn add @babel/preset-env --dev
1
2

它如何工作

@babel/preset-env是基于一些优秀的开源项目,比如browserslistopen in new windowcompat-tableopen in new windowelectron-to-chromiumopen in new window,要是没有它们,也就没有@babel/preset-env

我们利用这些数据源来维护一些映射表:

  • 我们支持的设备环境的哪个版本需要获得哪些 JavaScript 语法或浏览器特性的支持的映射
  • 这些语法和特性到 Babel 转换插件和core-jspolyfill的映射

注意

尤其需要注意的是,@babel/preset-env不支持stage-x的插件。

@babel/preset-env拿到你指定的目标环境,检查这些映射表来编译一系列的插件并传给 Babel。

Browserslist 集成

针对基于浏览器的或Electron-based的项目,我们推荐使用.browserslistrcopen in new window文件来指定目标环境。你可能已经有了这个配置文件,因为它会被生态系统里的许多工具用到,比如autoprefixeropen in new windowstylelintopen in new windoweslint-plugin-compatopen in new window等等。

若是没设置targetsignoreBrowserslistConfig配置项,@babel/preset-env默认会使用browserslist config sourcesopen in new window

比如,仅仅包含>0.25%市场份额浏览器的那些polyfill和代码转换:

Options:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        // 原文档是这样的
        // "useBuiltIns": "entry",

        // 实际上应该是这样
        "targets": "> 0.25%, not dead"
      }
    ]
  ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

browserslist:

> 0.25%
not dead
1
2

package.json:

{
    "browserslist": "> 0.25%, not dead"
}
1
2
3

Options

关于更多设置预设的配置项,可参考preset optionsopen in new window文档。

targets

string | Array<string> | { [string]: string },默认为{}

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

这可以使用browserslist-compatibleopen in new window形式的query

{
  "targets": "> 0.25%, not dead"
}
1
2
3

或者支持的最小环境版本的对象:

{
  "targets": {
    "chrome": "58",
    "ie": "11"
  }
}
1
2
3
4
5
6

这些环境可以是:

  • chrome
  • opera
  • edge
  • firefox
  • safari
  • ie
  • ios
  • android
  • node
  • electron

若是没有指定环境,@babel/preset-env默认将转换所有的 ECMAScript 2015+ 代码。

{
  "presets": ["@babel/preset-env"]
}
1
2
3

注意

我们不推荐使用preset-env时不指定环境,因为这样就无法发挥它指定目标浏览器能力的优势。

targets.esmodules

boolean

你要支持的目标浏览器可能支持ES 模块open in new window。当指定该选项,指定的目标浏览器将被忽略。你可以结合<script type="module"></script>来使用这样方式,这样就会产生更小的脚本文件(https://jakearchibald.com/2017/es-modules-in-browsers/#nomodule-for-backwards-compatibilityopen in new window)。

注意

请注意,当指定esmodules后,将忽略浏览器目标环境。

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "esmodules": true
        }
      }
    ]
  ]
}
1
2
3
4
5
6
7
8
9
10
11
12

targets.node

string | "current" | true

若是你想要针对当前node版本编译,你可以指定"node": true"node": "current",这与"node": process.versions.node是一样的。

targets.safari

string | "tp"

若是你想要针对 Safari 的 technology preview 版本编译,你可以指定"safari": "tp"

targets.browsers

即将在下个版本移除。

spec

boolean, 默认为false

Enable more spec compliant, but potentially slower, transformations for any plugins in this preset that support them.

loose

boolean, 默认为false

开启"loose" transformationsopen in new window,针对预设里允许loose转换的任何插件。

modules

"amd" | "umd" | "systemjs" | "commonjs" | "cjs" | "auto" | false,默认为"auto"

Enable transformation of ES6 module syntax to another module type.

开启将 ES6 模块语法转换为其他模块语法。设置为false将不转换模块。

cjscommonjs的别名。

debug

boolean, 默认为false

将使用的插件/目标环境以及plugin data versionopen in new window指定的版本输入到console.log

include

Array<string|RegExp>, 默认为[]

插件数组,这些插件总是被使用(即使目标环境不需要)。

有效的选项包括:

  • Babel 插件,带前缀或不带前缀都支持,比如@babel/plugin-transform-spreadplugin-transform-spread
  • 内置对象,比如es6.mapes6.set、或es6.object.assign

插件名称可以全部或部分指定(或使用正则表达式)。

可接受的输入有:

  • 全部名称,string"es6.math.sign"
  • 部分名称,string"es6.math.*"(解析为所有以es6.math为前缀的插件)
  • RegExp对象:/^transform-.*$/new RegExp("^transform-modules-.*")

注意,上面的.RegExp的一部分,等同于任何字符,而不是实际的字符.。另外注意在RegExp里使用.*匹配任何字符,类似于glob格式里的*

若是原生实现里有bug,或者只实现了特性的一部分时,这个配置项将尤其有用。

比如,Node 4 支持原生的类但是不支持函数参数的扩展运算符。若是调用super时使用扩展运算符,则需要引入@babel/plugin-transform-classes进行转换。

注意

注意,includeexclude选项仅能作用于包含在预设里的插件。因此,若是使用include包含@babel/plugin-proposal-do-expressions插件或是使用exclude排除@babel/plugin-proposal-function-bind,都会抛错。若是想使用不包含在预设里的插件,可以直接添加在plugins里。

exclude

Array<string|RegExp>,默认为[]

插件数组,这些插件将不会被使用(即使目标环境需要)。

可能的选项与include相同。

该选项设置了一个转换插件的黑名单,比如不使用@babel/plugin-transform-regenerator,若是你不使用生成器函数generators以及不想包含regeneratorRuntime(当使用useBuiltIns时)或使用另一个插件比如fast-asyncopen in new window而不是Babel 的async-to-genopen in new window

useBuiltIns

"usage" | "entry" | false,默认是false

注意

该选项会直接添加对core-js模块的引用。因此core-js将相对于文件自身进行解析,这要求core-js是可访问的。在你的项目,若是没有core-js依赖或是有多个版本,你可能需要指定core-js@2作为顶级依赖。

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

useBuiltIns: 'entry'

注意

整个项目里能且仅能有一次使用require("@babel/polyfill");。多次引入@babel/polyfill将抛错,因为这将导致全局冲突以及其他难以追踪的问题。我们推荐创建一个单独的入口你文件,仅仅包含require语句。

该选项启用一个新的插件,该插件将基于你环境单独引入core-js的各个文件,以此来替换掉import "@babel/polyfill"require("@babel/polyfill")语句。

npm install @babel/polyfill --save
1

输入:

import "@babel/polyfill";
1

输出(基于环境而不同):

import "core-js/modules/es7.string.pad-start";
import "core-js/modules/es7.string.pad-end";
1
2

这对直接引入core-js也是有效的(import "core-js";require('core-js');)。

useBuiltIns: 'usage'(实验性的)

添加对每个文件中使用的特定的polyfill的引入。我们利用了“一个打包文件将只加载一次相同的polyfill”这一事实。

输入:

// a.js
var a = new Promise();
1
2
// b.js
var b = new Map();
1
2

输出(若是环境不支持):

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

输出(若是环境支持):

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

useBuiltIns: false

每个文件里不自动添加polyfill,或不将import "@babel/polyfill"转换为单独的polyfill

forceAllTransforms

boolean,默认为false

有了 Babel 7 的Javascipt config fileopen in new window支持,若是env被设置为product,你可以强制使用所有的转换。

module.exports = function(api) {
  return {
    presets: [
      [
        "@babel/preset-env",
        {
          targets: {
            chrome: 59,
            edge: 13,
            firefox: 50,
          },
          // for uglifyjs...
          forceAllTransforms: api.env("production"),
        },
      ],
    ],
  };
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

注意

targets.uglify已经废弃并将在下个主版本移除。

默认情况下,这个预设将会按需运行目标环境需要的所有转换。若是你想要运行所有的转换(而忽略目标环境是否需要),则需要开启该选项,这对于输出代码在 UglifyJS 上或仅支持 ES5 的环境上运行来说将是非常有用的。

注意

Uglify 有一个在建的"Harmony"分支来设法解决 ES6 支持缺失的问题,但是这还不太稳定。你可以在UglifyJS2 issue #448open in new window关注这个进度。如果你想要一个支持 ES6 语法的可选的压缩工具,我们推荐使用babel-minifyopen in new window

configPath

string,默认为process.cwd()

搜索 Browserslist 配置的开始点,会基于此开始点向上搜索到系统根目录,直到发现配置文件。

ignoreBrowserslistConfig

boolean,默认为false

切换是否使用browserslist config sourcesopen in new window,这将决定是否要搜索任何的 Browserslist 配置文件或package.json里的browserslist选项。当项目里存在 Browserslist 配置文件但是不用于 Babel 编译时,这将非常有用。

shippedProposals

切换是否开启对处于提案中的且浏览器已经实现的内置对象/特性的支持。若是你的目标环境已经有了对某提案特性的原生支持,将开启与其相匹配的解析器语法插件,而不是执行任何的转换。注意,这不会开启与@babel/preset-stage-3open in new window相同的转换,因为这些提案在正式落地到浏览器之前还会继续改变。

当前以下内容是支持的:

Builtins

Features

  • None

@vue/babel-preset-env

@vue/babel-preset-envopen in new window是针对 Vue.js 项目,基于@babel/preset-env@vue/babel-preset-jsx@babel/plugin-transform-runtime等等预设和插件的封装,主要包含了以下内容:

  • @babel/preset-envopen in new window:主要使用该预设,并基于用户输入和目标环境等对参数进行了处理。
    • polyfills
      • @vue/babel-preset-env里默认包含了以下polyfill,详见源码open in new window,但是这些polyfill会根据目标环境来确定最终是否会传入@babel/preset-env预设里。假设目标环境都实现了这些内置对象或特性,则最终不会包含这些polyfill。详见源码open in new window
        • es6.array.iterator
        • es6.promise
        • es6.object.assign
        • es7.promise.finally
  • @babel/plugin-transform-runtimeopen in new window:仅使用了该插件引入模块化的helpers替换内联的 Babelhelpers
  • @babel/plugin-syntax-dynamic-import
  • @babel/plugin-proposal-decorators
  • @babel/plugin-proposal-class-properties
  • 等等