const a = [1, 2, 3, 4, 5];
const b = a.map(n => n * 10);
const c = Symbol();
to
"use strict";
require("core-js/modules/es7.symbol.async-iterator");
require("core-js/modules/es6.symbol");
require("core-js/modules/es6.array.map");
var a = [1, 2, 3, 4, 5];
var b = a.map(function (n) {
return n * 10;
});
var c = Symbol();
babel-preset-env
是我们现在常用的babel转换插件,相较于它的前任babel-preset-latest
,它有更加丰富的配置接口来减少我们的代码体积。背景
如果我们在项目用用到了es5+的新特性,又要项目支持版本较低的浏览器,我们通常会引入
babel-polyfill
来转换一些特定的对象,比如Symbol
之类的,如果是用import 'babel-polyfill'
这种方式,会将整个polyfill打包到我们的代码中,哪怕我们仅仅是用到了一个特性而已,这是一种浪费,有没有什么方法可以做到按需引入呢?core-js
core-js
是一个用户JavaScript的模块化标准库,babel-polyfill
就是基于它提供了一个完成的ES5+的环境。传统的使用
babel-polyfill
的方式是在类似entry这样的入口文件里引用,以保证polyfill的代码在所有其他代码之前生效,但是要做到最严格的按需引入,最直接的方法就是,一个文件里用到了哪些特性,就在文件头部引入哪些特性,为了防止某一个特性被重复引入,大约有两种办法:webpack
之类的构建工具,将这些polyfill打包成一个独立的包;而且更加难处理的就是,你不知道某些特性原生浏览是否已经实现了,如果浏览器实现了的话再引入polyfill就显得比较多余了。
targets && useBuiltIns
退而求其次,我们用
babel-preset-env
提供的一个更加自动化的方法来实现。为什么是退而求其次呢?因为这个还算不上严格意义上的按需引入。首先
babel-preset-env
有一个配置项targets
,它接受一个对象,用于配置需要支持的运行环境,我们可以在这里配置{"chrome": 52}
,表示最低只需要支持到Chrome的52.0.0
版本,配合兼容性表就可以得知某个特性是否需要polyfill,事实上,babel是通过定期运行build-data.js来生成plugins.json的。还有最重要的一点就是
useBuiltIns
选项,这个选项是一个Boolean,默认是false,也就是什么都不会发生。如果配置成true,那么babel就会替换掉我们的import 'babel-polyfill'
或者require('babel-polyfill')
,替换成什么呢?babel会自动引入我们浏览还未实现的特性,但是不会管你代码里到底有没有用到这些,所以说不是严格意义上的按需引入。
未来已来
讲了半天按需引入,如隔靴搔痒,很不痛快。 但是最近babel7的出现了,也带来了新的
@babel/preset-env
,新的useBuiltIns支持"usage"
|"entry"
|false
。不配置(默认
false
)配置成false
还是和以前一样什么都不发生。配置成
"entry"
,和babel@6.x时配置成"true"
的表现一样。最骚的是
"usage"
,首先,不需要在业务代码里手动引入babel-polyfill
,babel会根据targets支持情况,结合你代码里使用到的特性,自动在打包后的代码里按需引入,一下是我配置支持到IE 8的代码:to
非常完美,就是不太稳定,截止到目前还是
beta.51
版本,耐心等下吧。