babel-preset-env:一个帮你配置babel的preset

时间: 2018-04-10阅读: 47标签: babel

babel-preset-env 一个帮你配置babel的preset,根据配置的目标环境自动采用需要的babel插件。


问题

目前,几个presets就能让你确定babel应该支持那些功能:

  • babel-preset-es2015, babel-preset-es2016等:支持不同版本的ECMAScript规范。 es2015 转译了ES6比ES5的新特性, es2016 转译了ES2016比ES6的新特性等等。
  • babel-preset-latest: 支持现有所有ECMAScript版本的新特性,包括处于stage 4里的特性(已经确定的规范,将被添加到下个年度的)。

问题是这些presets有时做的多余了,举个例子,大部分现代浏览器已经支持ES6的generators了,但是如果你设置了babel-preset-es2015,generator函数还是会被转译成复杂的ES5代码。


解决方案

babel-preset-env 功能类似 babel-preset-latest,优点是它会根据目标环境选择不支持的新特性来转译。

note:实验性的属性(babel-preset-latest不支持的)需要手动安装配置相应的plugins或者presets。这样你再不需要 es20xx presets了。

浏览器

你可以选择指定相应的浏览器配置:

  • browsers参数在这里查询 browserslist . 举个例子:

    • 支持每个浏览器最近的两个版本和IE大于等于7的版本所需的polyfill和代码转译。

      "babel": {
        "presets": [
          [
            "env",
            {
              "targets": {
                "browsers": ["last 2 versions", "ie >= 7"]
              }
            }
          ]
        ]
      },
      
      
    • 支持市场份额超过5%的浏览器。

      "targets": {
        "browsers": "> 5%"
      }
      
      
  • 指定浏览器版本:

     "targets": {
       "chrome": 56
     }
    
    

Node.js

如果你通过Babel编译你的Node.js代码,babel-preset-env 很有用,设置 "targets.node" 是 "current",支持的是当前运行版本的nodejs:

"babel": {
  "presets": [
    [
      "env",
      {
        "targets": {
          "node": "current"
        }
      }
    ]
  ]
},

我的GitHub上有个测试node参数的例子,请参考 async-iter-demo.


其他配置

下面会列举 babel-preset-env部分常用配置。所有配置请查看点击 env preset; 中文版本

modules (string, 默认值: "commonjs")

将ES6模块语法转换为另一种模块类型,可选值:

  • 各种流行的模块化规范:"amd"、 "commonjs"、 "systemjs"、 "umd"
  • 禁止转译:false

include, exclude (Array of strings, 默认值: [])

  • include 必须要转译的功能 (比如 覆盖有故障的本地功能)。跟单独启用相应插件是一样的。
  • exclude 禁止转译的功能。

useBuiltIns (boolean, 默认值: false)

babel为标准库中的新功能提供了polyfill,为内置对象,静态方法,实例方法,生成器函数提供支持。 babel-preset-env可以实现基于特定环境引入需要的polyfill。

两种使用方法:

  • core-js, 根据需要引入ES5,ES6+标准方法的实现。
    • 安装 polyfill: npm install core-js --save
    • 引入 polyfill: import "core-js";
  • babel-polyfill 包含core-js 和regenerate-runtime (提供 async 语法编译后的运行时环境)。
    • 安装 polyfill: npm install babel-polyfill --save
    • 引入 polyfill: import "babel-polyfill";

两种方法最终都会根据环境转译成特定的polyfill。 比如:

import "core-js/modules/es7.string.pad-start";
import "core-js/modules/es7.string.pad-end";
import "core-js/modules/web.timers";
import "core-js/modules/web.immediate";
import "core-js/modules/web.dom.iterable";

note:

  • 在整个应用里只能引入一次polyfill,可以在 “main” 模块里一次引入。
  • useBuiltIns 会使浏览器下载的代码变少 (最终打包的文件大小变小了)。但是不会节约内存, 因为polyfill本身只会安装缺少的部分。

更多polyfill的内容请参考《Setting up ES6》中的章节:“Babel: configuring standard library and helpers

debug (boolean, default: false)

以下内容都会用console.log输出 :

  • 目标环境
  • 启用的transforms
  • 启用的plugins
  • 启用的polyfills

尝试下面的示例,瞧瞧console输出。

举例

下面的例子选自preset的readme文件:

{
  "presets": [
    [ "env", {
      "targets": {
        "safari": 10
      },
      "modules": false,
      "useBuiltIns": true,
      "debug": true
    }]
  ]
}

模块不会被转译,可以将imports和exports让webpack去处理。

debug 的输出如下:

Using targets:
{
  "safari": 10
}

Modules transform: false

Using plugins:
  transform-exponentiation-operator {}
  transform-async-to-generator {}

Using polyfills:
  es7.object.values {}
  es7.object.entries {}
  es7.object.get-own-property-descriptors {}
  web.timers {}
  web.immediate {}
  web.dom.iterable {}


env是如何基于目标环境去匹配哪些是需要转译的?

根据以下外部数据来确定目标环境支持的情况,可以定期执行build-data.js 来生成 plugins.json

下一步还能做什么?

有可以访问‘环境’ 的插件

未来计划让插件拥有检查当前环境具有什么可能性的能力,两个好处:

  • 一些plugins (比如对象扩展运算符) 目前通过选项告诉他们是否使用本地功能或polyfills。如果能知道当前 “环境”,就不需要配置了。

  • 基于babel的minifiers可以确定是否可以输出。比如,箭头函数。

简化presets

  • 基于ECMAScript版本的Presets (es2015 等)很多已经过时了 。Babel团队考虑会在未来的版本中移除他们 (比如, 通过废弃处理)。

  • 基于TC39不同阶段的提案的Presets (stage-0,1,2,3等) 也是去除的候选,因为在这些statges中的标准是不断变化的。提案可以在2个月内改变。因此,直接引用一些实验性的plugins会是更好的选择。

感谢

延伸阅读