再见,babel-preset-2015

3,371 阅读5分钟
原文链接: zhuanlan.zhihu.com

我猜很多同学和我一样每次使用 Babel 的时候,必选的 preset 就是 ES2015。

然而就在最近,如果你再次安装 babel-preset-es2015 时

npm install --save-dev babel-preset-es2015

你会发现有如下的 Deprecated警告(文字很欢乐):

babel-preset-es2015@6.24.1: We're super 😸 excited that you're trying to use ES2015 syntax, but instead of making more yearly presets 😭 , Babel now has a better preset that we recommend you use instead: npm install babel-preset-env --save-dev. preset-env without options will compile ES2015+ down to ES5 just like using all the presets together and thus is more future proof. It also allows you to target specific browsers so that Babel can do less work and you can ship native ES2015+ to user 😎 ! We are also in the process of releasing v7, so please give babeljs.io/blog/2017/09 a read and help test it out in beta! Thanks so much for using Babel 🙏, please give us a follow on Twitter @babeljs for news on Babel, join slack.babeljs.io for discussion/development and help support the project at opencollective.com/babel

是的,在2017年第三季度我们终于要和 ES2015 preset 说再见了。

那么你可能会问我们是要迁移到 ES2017 了吗?事实上并非如此,babel-preset-es2017 只是增加了一些特性而已,且仍然需要安装 ES2015。好了,不卖关子了,答案就是——

你好,babel-preset-env

Babel 的官网上在9月宣布 ES2015 / ES2016/ ES2017 等等 ES20xx 时代的 presets 通通被废弃(deprecated),取而代之的是 babel-preset-env,并且承诺它将成为“未来不会过时的(future-proof)”解决方案。

在过去,Babel 将 babel-preset-es2015 放在 babel/babel 的主仓库中进行维护,而 babel-preset-env 则独立为一级项目,这从某种程度上也显示出 Babel 官方对这款 preset 的重视程度和更长远的规划。

如何迁移

为了节省你的阅读时间,我先给出一个如何升级的简单版:

首先卸载原来的 preset,然后安装 babel-preset-env:

npm uninstall --save-dev babel-preset-es2015
npm install --save-dev babel-preset-env

接下来将你的 .babelrc 文件中“es2015”修改“env”:

{
  "presets": [ "env" ],
  ...
}

好了,恭喜你,就这么简单,你已经可以与 ES2015+ 保持更新了!


更进一步

在 babel-preset-env 的官方说明中提到这是一款可以“自动”决定加载哪些插件和 polyfill 的 preset,既然是叫“env”,那么一定是可以由开发者决定编译目标处于什么样的运行环境。

targets 选项

通过 targets 指定需要兼容的浏览器类型和版本(采用 ai/browserslist 查询语法 ):

{
  "presets": [
    ["env", {
      "targets": {
        "browsers": ["last 2 versions", "safari >= 7"]
      }
    }]
  ]
}

换句话说,你可以通过指定更高的浏览器版本来减少插件和 polyfill 的代码量,并且直接使用原生 ES6 的新特性,特别适合 Electron 及移动端 App 或者那些已指定了浏览器的内网应用程序。例如,将浏览器设为 Chrome 较高的版本,Promise、Map、Set 等内建类均不会被 polyfill,而同时 class 等新语法也不会被 Babel 转译,转而使用 V8 自带的 ES6 Class。

如果你是用来开发 Node.js 应用,也同样可以指定 Node 的版本:

{
  "presets": [
    ["env", {
      "targets": {
        "node": "6.10"
      }
    }]
  ]
}
为了方便,你也可以直接写成 "node": "current",将自动采用你当前用来运行 Babel 的 Node.js 版本。
同时也可以在 targets 中指定 browsers 选项。

目前 targets 中支持了几乎所有主流运行时环境,其中就包括了 IE、Chrome、Firefox、Opera、Edge、Safari、iOS Safari、Android、Node 和 Electron 等。

modules 选项

该选项与过去一致,用来指定模块化方式,支持 AMD、UMD、SystemJS、CommonJS 等。当然在 Webpack 2/3 的时代,推荐将 modules 设置为 false,即交由 Webpack 来处理模块化,通过其 TreeShaking 特性将有效减少打包出来的 JS 文件大小:

{
  "presets": [
    ["env", {
      modules: false,
      ...
    }]
  ]
}
从 Webpack 2 开始,已自动启用对 Native Import 的支持,因此无需对 Webpack 进行额外设置,详情请参考我的另一个答案Henry Li:ECMAScript 6 的模块相比 CommonJS 的require (...)有什么优点?

useBuiltIns 选项与 Polyfill

这是一个关于 Polyfill 的选项,个人认为这是此次迁移后带来的最大便利,当然首先你仍然需要额外安装 babel-polyfill(是的,你不再需要额外的 transform)

npm install babel-polyfill --save

当 useBuiltIns 设置为 usage 时,Babel 会在你使用到 ES2015+ 新特性时,自动添加 babel-polyfill 的引用,并且是 partial 级别的引用。

例如:

const promise = new Promise();
const map = new Map();

会被转译为:

import "babel-polyfill/core-js/modules/es6.map";
import "babel-polyfill/core-js/modules/es6.promise";

var promise = new Promise();
var map = new Map();

很多人习惯于在 vendor 中一次性引入 babel-polyfill,在过去这将导致整个 babel-polyfill 包被打包到 vendor 中,在方便开发的同时失去了灵活性,而现在你可以将 useBuiltIns 设置为 entry,Babel 会自动进行优化:

例如:

vendor.js :

import 'babel-polyfill';

index.js:

const promise = new Promise();
const map = new Map();

最终 vendor.js 会被转译为:

import "babel-polyfill/core-js/modules/es6.map";
import "babel-polyfill/core-js/modules/es6.promise";

怎么样?是不是超级“智能”!

再见,babel-preset-es2015

现在,我们可以放心的说,是时候和 babel-preset-es2015 告别了。

babel-preset-env 目前正在不断积极更新中,更多的 babel-preset-env 选项请参见 babel/babel-preset-env


关于专栏

如果你喜欢这篇文章,就请关注我的专栏《前端零栈》,在这里我们一起聊一聊前端技术和前端工程。

《前端零栈》专栏开张后,共先后发表过两篇文章,非常有幸这两篇均被友商选入周刊推荐,欢迎关继续注我的专栏前端零栈 - 知乎专栏

关于作者

Henry,就职于阿里巴巴南京研发中心,10 岁开始学习计算机编程,高二暑假获得江苏省青少年信息奥林匹克一等奖。2000 年开始自学 JavaScript 及网页制作,2006 年起正式开始从事前端开发工作,从此一干就是 10 多年。加入阿里巴巴前,曾在 SAP 中国研究院担任智慧交通大数据产品经理。

Github:MagicCube (Henry Li)