引言
babel 从 6 开始有 preset 的概念,用来组织繁杂的插件,其实就相当于快捷方式,帮助你快速指定需要的插件组合。比如 babel-preset-react,只需要指定这一个 preset,就可以使用 react 开发所需的插件,包括 babel-plugin-syntax-jsx 等。
preset 和 js 的标准提案
除了 react preset 外,官方维护 preset 还有这些:
- flow:包含 flow type 所需插件
- es2015:包含 es2015 语法标准所有相关插件
- es2016:包含 es2016 语法标准所有相关插件
- es2017:包含 es2017 语法标准所有相关插件
- latest:包含从 2015 开始历年语法标准所有相关插件
- env:在 latest 基础上提供环境配置能力,比如可以配置只支持某一个浏览器的某几个版本,会自动按需启用、禁用插件
- stage-0:包含处于标准提案 stage 0 阶段的语法所有相关插件
- stage-1:包含处于标准提案 stage 1 阶段的语法所有相关插件
- stage-2:包含处于标准提案 stage 2 阶段的语法所有相关插件
- stage-3:包含处于标准提案 stage 3 阶段的语法所有相关插件
那么 es2015, stage-0 等等这些之间到底是什么关系呢?
js 有很长的历史,中间有多年停滞不前,不但没有任何改进,还因为浏览器大战导致极度混乱。但是随着互联网繁荣,前端对 js 越来越倚重,再加上服务端 node.js 兴起,促使社区成立了标准委员会,开始推进 js 的升级,这个委员会叫做 TC39。
他们负责讨论和改进标准提案,最终通过后,会将多个提案整理到某一年的发布中。es2015 就是第一个发布。
中间每一个提案,都要依次经过 stage 0、stage 1、stage 2、stage 3、stage 4 五个阶段。其中到达 stage4 的为已通过,会出现在下一年的发布中。到达 stage3 的属于比较成熟的,极有可能在较小改动的前提下通过并发布,stage3 之前的则不太成熟,stage 越往前越容易大幅改动甚至被完全去掉。所以对于开发者来说,使用 stage 3 之前的语法有一定风险。
知道了这些,babel 的这些 preset 也就不难理解,es20xx 的,都是已经正式通过并在那一年发布的,stage-x 的都是还在讨论中,不太稳定的。
在这里可以查看各个提案的状态:
我们以 Rest/Spread Properties 为例,该提案处在 stage 3,所以如果你想使用包含它的 preset,应该使用 babel-preset-stage-3(当然你始终可用直接指定插件 babel-plugin-transform-object-rest-spread 而非 preset)。
我之前用的时候看到 babel-preset-latest,以为它包含了所有的,实际它只包含了所有正式发布的。😢
示例
babel 的最佳实践是使用 babel-preset-env,示例配置文件 .babelrc 如下:
{
"presets": [
["env", {
"targets": {
"node": "current",
"browsers": "last 2 versions"
}
}]
]
}
相当于声明“我需要支持当前使用的 node.js 版本,以及主流浏览器的最近两个版本”,该 preset 会自动启用先关插件以满足这个需求。
假设我们当前使用的 node.js 版本是 v7.7.4,有如下代码 demo.js:
import { MongoClient } from 'mongodb';
async function run() {
const db = await MongoClient.connect('mongodb://localhost/test');
console.log(db);
}
run();
执行 babel demo.js 得到编译结果:
'use strict';
var run = function () {
var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee() {
var db;
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return _mongodb.MongoClient.connect('mongodb://localhost/test');
case 2:
db = _context.sent;
console.log(db);
case 4:
case 'end':
return _context.stop();
}
}
}, _callee, this);
}));
return function run() {
return _ref.apply(this, arguments);
};
}();
var _mongodb = require('mongodb');
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
run();
编译结果是较复杂的,主要是因为现在主流浏览器还不支持 async/await,babel 做了很多工作。实际上即便如此编译出来,也是不能直接在浏览器跑的(不考虑我这里用 mongodb 的库作为例子),还需要引入 generator 运行时。
如果我们把上面配置中的 "browsers": "last 2 versions" 去掉,只留下 "node": "current",编译结果则简单许多,因为我们所使用的 v7.7.4 版 node.js 已经原生支持 async/await,babel 不再需要额外处理,如下:
'use strict';
var _mongodb = require('mongodb');
async function run() {
const db = await _mongodb.MongoClient.connect('mongodb://localhost/test');
console.log(db);
}
run();
引言
babel 从 6 开始有 preset 的概念,用来组织繁杂的插件,其实就相当于快捷方式,帮助你快速指定需要的插件组合。比如 babel-preset-react,只需要指定这一个 preset,就可以使用 react 开发所需的插件,包括 babel-plugin-syntax-jsx 等。
preset 和 js 的标准提案
除了 react preset 外,官方维护 preset 还有这些:
那么 es2015, stage-0 等等这些之间到底是什么关系呢?
js 有很长的历史,中间有多年停滞不前,不但没有任何改进,还因为浏览器大战导致极度混乱。但是随着互联网繁荣,前端对 js 越来越倚重,再加上服务端 node.js 兴起,促使社区成立了标准委员会,开始推进 js 的升级,这个委员会叫做 TC39。
他们负责讨论和改进标准提案,最终通过后,会将多个提案整理到某一年的发布中。es2015 就是第一个发布。
中间每一个提案,都要依次经过 stage 0、stage 1、stage 2、stage 3、stage 4 五个阶段。其中到达 stage4 的为已通过,会出现在下一年的发布中。到达 stage3 的属于比较成熟的,极有可能在较小改动的前提下通过并发布,stage3 之前的则不太成熟,stage 越往前越容易大幅改动甚至被完全去掉。所以对于开发者来说,使用 stage 3 之前的语法有一定风险。
知道了这些,babel 的这些 preset 也就不难理解,es20xx 的,都是已经正式通过并在那一年发布的,stage-x 的都是还在讨论中,不太稳定的。
在这里可以查看各个提案的状态:
我们以 Rest/Spread Properties 为例,该提案处在 stage 3,所以如果你想使用包含它的 preset,应该使用 babel-preset-stage-3(当然你始终可用直接指定插件 babel-plugin-transform-object-rest-spread 而非 preset)。
我之前用的时候看到 babel-preset-latest,以为它包含了所有的,实际它只包含了所有正式发布的。😢
示例
babel 的最佳实践是使用 babel-preset-env,示例配置文件
.babelrc如下:{ "presets": [ ["env", { "targets": { "node": "current", "browsers": "last 2 versions" } }] ] }相当于声明“我需要支持当前使用的 node.js 版本,以及主流浏览器的最近两个版本”,该 preset 会自动启用先关插件以满足这个需求。
假设我们当前使用的 node.js 版本是 v7.7.4,有如下代码
demo.js:执行
babel demo.js得到编译结果:编译结果是较复杂的,主要是因为现在主流浏览器还不支持 async/await,babel 做了很多工作。实际上即便如此编译出来,也是不能直接在浏览器跑的(不考虑我这里用 mongodb 的库作为例子),还需要引入 generator 运行时。
如果我们把上面配置中的
"browsers": "last 2 versions"去掉,只留下"node": "current",编译结果则简单许多,因为我们所使用的 v7.7.4 版 node.js 已经原生支持 async/await,babel 不再需要额外处理,如下: