8

babel-preset-env:你需要的唯一Babel插件

justjavac 2017年02月24日 发布于前端 www.2ality.com

babel-preset-env 是一个新的 preset,可以根据配置的目标运行环境(environment)自动启用需要的 babel 插件。

目前我们写 javascript 代码时,需要使用 N 个 preset,比如:babel-preset-es2015、babel-preset-es2016。es2015 可以把 ES6 代码编译为 ES5,es2016 可以把 ES2016 代码编译为 ES6。babel-preset-latest 可以编译 stage 4 进度的 ECMAScript 代码。

问题是我们几乎每个项目中都使用了非常多的 preset,包括不必要的。例如很多浏览器支持 ES6 的 generator,如果我们使用 babel-preset-es2015 的话,generator 函数就会被编译成 ES5 代码。

babel-preset-env 的工作方式类似 babel-preset-latest,唯一不同的就是 babel-preset-env 会根据配置的 env 只编译那些还不支持的特性。

使用这个插件,你讲再也不需要使用 es20xx presets 了。

配置语法和 Autoprefixer 一样......

babel-preset-env:你需要的唯一Babel插件

2017年02月24日 发布,来源:www.2ality.com

babel-preset-env is a new preset that lets you specify an environment and automatically enables the necessary plugins.

The problem

At the moment, several presets let you determine what features Babel should support:

  • babel-preset-es2015, babel-preset-es2016, etc.: incrementally support various versions of ECMAScript. es2015 transpiles what’s new in ES6 to ES5, es2016 transpiles what’s new in ES2016 to ES6, etc.
  • babel-preset-latest: supports all features that are either part of an ECMAScript version or at stage 4 (which basically means the same thing).

The problem with these presets is that they often do too much. For example, most modern browsers support ES6 generators. Yet, if you use babel-preset-es2015, generator functions will always be transpiled to complex ES5 code.

The solution

babel-preset-env works like babel-preset-latest, but it lets you specify an environment and only transpiles features that are missing in that environment.

Note that that means that you need to install and enable plugins and/or presets for experimental features (that are not part of babel-preset-latest), yourself.

On the plus side, you don’t need es20xx presets, anymore.

Browsers

For browsers you have the option to specify either:

  • Browsers via browserslist query syntax. For example:

    • Support the last two versions of browsers and IE 7+.

       "babel": {
       "presets": [
       [
       "env",
       {
       "targets": {
       "browsers": ["last 2 versions", "ie >= 7"]
       }
       }
       ]
       ]
       },
      
    • Support browsers that have more than 5% market share.

       "targets": {
       "browsers": "> 5%"
       }
      
  • Fixed versions of browsers:

     "targets": {
     "chrome": 56
     }
    

Node.js

If you compile your code for Node.js on the fly via Babel, babel-preset-env is especially useful, because it reacts to the currently running version of Node.js if you set the target "node" to "current":

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

If you want to see this target in action, take a look at my GitHub repository async-iter-demo.

Additional options for babel-preset-env

This section gives a brief overview of additional options for babel-preset-env. For details, consult the preset’s readme file.

modules (string, default: "commonjs")

This option lets you configure to which module format ES6 modules are transpiled:

  • Transpile to popular module formats: "amd", "commonjs", "systemjs", "umd"
  • Don’t transpile: false

include, exclude (Array of strings, default: [])

  • include always enables certain plugins (e.g. to override a faulty native feature). It has the same effect as enabling plugins separately.
  • exclude prevents certain plugins from being enabled.

useBuiltIns (boolean, default: false)

Babel comes with a polyfill for new functionality in the standard library. babel-preset-env can optionally import only those parts of the polyfill that are needed on the specified platform(s).

There are two ways of using the polyfill:

  • core-js polyfills ES5, ES6+ as needed.
    • Install polyfill: npm install core-js --save
    • Activate polyfill: import "core-js";
  • babel-polyfill polyfills core-js and the regenerator runtime (to emulate generators on ES5).
    • Install polyfill: npm install babel-polyfill --save
    • Activate polyfill: import "babel-polyfill";

Either of the two import statements is transpiled to an environment-specific sequence of more fine-grained imports. For example:

 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";

Things to note:

  • You should activate the polyfill exactly once in your program, e.g. in a “main” module.
  • useBuiltIns means that less code is downloaded to the browser (bundle sizes become smaller). However, it does not save RAM, because the polyfill only installs what is missing.

For more on polyfilling the standard library, consult chapter “Babel: configuring standard library and helpers” in “Setting up ES6”.

debug (boolean, default: false)

Logs the following information via console.log():

  • Targeted environments
  • Enabled transforms
  • Enabled plugins
  • Enabled polyfills

Check the next section for sample output.

Example

The following example is taken from the preset’s readme file:

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

Modules are not transpiled. We can, e.g., rely on webpack to handle imports and exports for us.

The debug output is as follows:

 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 {}

Where does babel-preset-env get its information?

  • The features supported by a given JavaScript engine are determined via kangax’s compat-table.
  • Features are mapped to plugins via the file plugin-features.js.
  • browserslist enables queries such as "> 1%" and "last 2 versions".

What’s next?

Giving plugins access to their “environment”

Plans for the future include giving plugins the ability to examine what is possible in the current “environment”. That would have two benefits:

  • Some plugins (such as the one for the object spread operator) currently have options telling them whether to use native functionality or polyfills. If they were aware of their “environment”, the plugins wouldn’t need those options.

  • Babel-based minifiers can determine whether it’s OK to output, e.g., arrow functions.

Simplifying presets

  • Presets based on ECMAScript versions (es2015 etc.) are mostly made obsolete by env. The Babel team is considering eliminating them in future Babel releases (e.g. via a deprecation process).

  • Presets based on stages of the TC39 process (stage-3 etc.) are also candidates for removal, as things related to stages are in constant flux. You can’t really rely on anything in this space, because the stage of a proposal can change within 2 months. Therefore, directly referring to plugins of experimental features is the better approach.

Acknowledgements

  • Thanks to Henry Zhu for all the useful input for this blog post.

Further reading

28.4k 浏览 16 收藏 报告 阅读模式
25 条评论
神采飞扬 · 2017年05月09日

长见识了

+1 回复

Zhzxiansheng · 2018年06月11日

大神,是不是用了这个就不需要用 babel-preset-es2015 了?

回复

0

不需要了,而且 es2015 早就过时了

justjavac 分享者 · 2018年06月11日
0

多谢

不懂 · 2018年06月11日
eddyzhang1986 · 2018年03月30日

我很负责任的告诉你们,楼主说的完全是错误的,这个插件是为了解决目标平台不同,而不是像楼主说的那样https://www.cnblogs.com/ye-hc...

回复

1

你宁可相信一个二手资料,也不相信官网吗 https://babeljs.io/docs/plugi...

justjavac 分享者 · 2018年03月30日
0

...你竟然不知道jjc,然后还“负责任的告诉我们”。。。

tachi · 2018年04月02日
0

@tachi 一点也不负责任 23333

justjavac 分享者 · 2018年04月02日
天然空 · 2017年09月24日

这个东西好像无法兼容ie8哦,即使使用new es3ifyPlugin()

回复

0

和IE8没有关系,这个只是 preset,不包括 plofill

justjavac 分享者 · 2017年09月25日
yuechen323 · 2017年07月06日

大神不太懂啊, 你代码上线的时候, 用npm build, 不是就是已经编译完的了吗? 已经确定了是最终编译成es5或者es6 怎么还能动态编译呢, 不太懂? 你都部署到了nginx后, 大家别管浏览器是啥, 使用的代码应该都是一样的啊

回复

0

这个就是静态编译的,编译的时候你 env 的 target 来决定哪些特性需要编译,哪些 plyfill 需要加载

justjavac 分享者 · 2017年07月06日
0

这个和你说的不一样 这里边所谓的动态是指 比如你的代码中有用stage-0的新的东西,编译的时候babel-preset-env会自动找stage-0对应的模块去编译你的代码。而不需要再自己去手动配置了

bean · 2017年11月22日
歪泥偶巴 · 2017年06月29日

如何配置成为ES5的代码??

回复

0

默认就是 es5

justjavac 分享者 · 2017年09月25日
hack · 2017年06月23日

babel-preset-env是不是包含了所有的插件 比如babel-preset-es2015、babel-preset-es2016 、babel-polyfill、babel-react ... ?

回复

0

包括了所有的 babel-preset-es 和 babel-preset-stag,但是不包括 polyfill 和 react 。。。

justjavac 分享者 · 2017年06月24日
0

@justjavac 谢谢大神

hack · 2017年06月26日
0

不包括polyfill它如何支持ES6的api呢?

alwaysVe · 2017年07月17日
载入中...