[译]babel-preset-env
看了两个webpack2基础的视频教程, 发现两位老师所用的babel-preset的差异, 于是查了一下两者的区别, 看到了一篇相关的文章, 尝试将其翻译. 原文: babel-preset-env: a preset that configures Babel for you.
使用babel-preset-env
, 可以另外声明环境, 然后该preset根据你的声明自动激活必要的插件.
存在的问题
现在, 有多个preset让我们选择, 以决定Babel应该支持编译具有哪一些特性的代码:
babel-preset-es2015
,babel-preset-es2016
等: 增量支持不同版本的ECMAScript. babel-preset-es2015将含有ES6新特性的代码编译为ES5下的代码, babel-preset-es2016则将含有ES2016新特性的代码编译为ES6下的代码.babel-preset-latest
: 支持编译所有ECMAScript版本下特性或处于stage4阶段的特性的代码(实际上两者是差不多的).
这些preset的问题就是: 它们都太”重”了, 即包含了过多在某些情况下不需要的功能. 比如, 现代的浏览器大多支持ES6的generator, 但是如果你使用babel-preset-es2015, 它会将generator函数编译为复杂的ES5代码, 这是没有必要的.
解决方案
babel-preset-env
和babel-preset-latest
的功能很相似, 但使用babel-preset-env, 我们可以声明环境, 然后该preset就会只编译包含我们所声明环境缺少的特性的代码.
要注意, 这就意味着我们需要自己另外去安装激活某些插件或preset以处理某些实验性特性(这些特性往往不是babel-preset-latest
的一部分).
使用babel-preset-env
的好处是: 你不再需要es20xx preset.
浏览器
对于特定的浏览器, 你也可以添加相关的配置:
根据browserslist对浏览器相关信息执行配置. 例如:
- 支持大部分浏览器最新的两个版本以及IE 7+:
1
2
3
4
5
6
7
8
9
10
11
12"babel": {
"presets": [
[
"env",
{
"targets": {
"browsers": ["last 2 versions", "ie >= 7"]
}
}
]
]
},- 支持超过市场份额5%的浏览器:
1
2
3"targets": {
"browsers": "> 5%"
}某个固定版本的浏览器:
1
2
3"targets": {
"chrome": 56
}
Node.js
如果你想要使用Babel实时编译Node的代码, babel-preset-env
就特别有用, 因为它支持在配置中将Node的版本声明为当前版本, 这样每一次都会对Node的最新版本执行编译.
1 | "babel": { |
想看实例可以查看这个GitHub repo: async-iter-demo
配置babel-preset-env
这部分简单介绍babel-preset-env的配置选项, 更多细节详见该preset的README文件.
模块系统(字符串, 默认为”common.js”)
配置你想要将ES6模块编译为哪一种模块系统:
编译为其他流行的模块系统: “amd”, “commonjs”, “systemjs”, “umd”
不编译, 还是使用ES6模块系统, 则将值声明为false.
include, exclude(数组, 默认为”[ ]”)
在include中声明的值一般是元素为插件名的数组, 表示在项目中使用这些插件(如改写有缺陷的原生特性的插件), 在include中一起声明和分别另外声明插件的效果是一样的.
在exclude中声明的值也是元素为插件名的数组, 但表示的是在项目中不可以使用这些插件.
useBuiltIns(布尔值, 默认为false)
Babel标准库本身含有针对新特性的polyfill. 使用babel-preset-env可以配置是否需要某一部分的polyfill.
使用polyfill有两种方式:
使用
core-js
polyfills(动词) ES5, ES6+的代码- 安装该polyfill:
npm install core-js --save
- 激活该polyfill:
import "core-js";
- 安装该polyfill:
使用
babel-polyfill
polyfillscore-js
和regenetator runtime(在ES5中模拟generator)- 安装该polyfill:
npm install babel-polyfill --save
- 激活:
import "babel-polyfill";
- 安装该polyfill:
两个中任何一个import声明都会被编译为针对特定环境的几个更细节的按顺序引入的import声明. 例如:
1 | import "core-js/modules/es7.string.pad-start"; |
需要注意的几点:
- 要确保某个需要的polyfill在项目中被激活一次, 比如在”main”模块中
- 使用
useBuiltIns
后, 浏览器下载的代码量就会变少(bundle.js文件更小). However, it does not save RAM, because the polyfill only installs what is missing.
要了解关于标准库中polyfill的更多信息, 可以查看”Setting up ES6”中的”Babel: configuring standard library and helpers“章节.
调试(布尔值, 默认为false)
通过console.log()
输出以下信息:
- 目标环境
- 使用的的转换规则
- 使用的插件
- 使用的polyfill
示例详见下一节.
示例
以下例子从babel-preset-env
的README文件中截取:
1 | { |
在以上示例中, 设置了不编译模块, 我们可以使用webpack来处理import与export.
调试的输出结果如下:
1 | Using targets: |
babel-preset-env如何获取并判断配置信息
不同的JavaScript引擎支持哪些特性的根据来源: kangax’s compat-table
plugin-features.js内声明了不同插件所含的特性
使用browserslist使preset理解”> 1%”和”last 2 versions”等所表明的浏览器信息
接下来要实现的功能
给予插件获取”环境”信息的权限
接下来的计划是给予插件检视在当前”环境”下可以实现哪些功能的能力. 这将带来两个好处:
某些插件(比如针对对象的扩展运算符插件)现在需要对其配置决定是使用原生的功能还是polyfill. 如果该插件可以获取环境信息, 就不再需要手动进行配置.
基于Babel的压缩插件有能力决定是否要对某些特性执行转换(如箭头函数).
简化preset
babel-preset-env
中不再支持大多数基于ECMAScript版本的preset(如babel-preset-es2015, babel-preset-es2016). Babel团队现在正考虑在将来的Babel release中淘汰这些preset(比如通过弃用的方式(deprecation process))基于TC39进程(如stage-3等)的preset也因stage的不稳定性即将被淘汰, 某个提案的stage很有可能在2个月就发生变化. 因此, 直接通过插件来添加某些实验性特性是个更好的方法.
扩展阅读
参考