@qinyun
2018-08-28T13:28:28.000000Z
字数 6288
阅读 1984
未分类
今天,Babel官方博客宣布正式推出Babel 7.0,在过去两年内,Babel 7经历了4000次提交,发布了50多个预览版本,这也是三年前发布v6.0之后的最大更新。
由于JavaScript在不断地发展,各种新标准和提案也就层出不穷,用户使用的浏览器也不同(尤其是旧版的IE),这就导致了有些用户无法使用JavaScript的一些新特性,如果开发人员想使用新的语法(如class A {}),在旧浏览器上就会因为这个问题出现SyntaxError。
由于它能够转换JavaScript代码,还可用于实现新功能,因此它已成为TC39获得社区对JavaScript反馈的桥梁。
如今,Babel是JavaScript开发的基础。它在npm上,每月有1700万次的下载量,用户来自主流框架(React,Vue,Ember,Polymer)的开发者和企业(Facebook,Netflix,Airbnb)。即使你自己没有使用它,你的依赖项也很可能正在使用Babel。
虽然Babel对JavaScript语言的未来,甚至对社区和js生态都产生了巨大的影响,但你肯定想不到,他们的维护者只是由社区的几个志愿者组成。
不再支持不在维护中的Node版本:0.10、0.12、4、5;
使用@babel命名空间,因此babel-core就变成了@babel/core;
移除(并停止发布)任何年度预设(preset-es2015等),@babel/preset-env取代了对这些内容的需求;
移除“Stage” 预设(@babel/preset-stage-0等),同时移除了@babel/polyfill中的提议;
重命名了某些包:任何TC39提议插件现在都是-proposal而不是-transform,所以@babel/plugin-transform-class-properties变成了@babel/plugin-proposal-class-properties;
针对某些面向用户的包(例如babel-loader、@babel/cli等)在@babel/core中引入peerDependency;
babel-upgrade是一个用于进行自动升级的新工具:目前在package.json和.babelrc配置文件中配置了依赖关系。
我们建议直接在git仓库上运行npx babel-upgrade,或者使用npm i babel-upgrade -g进行全局安装。
如果你想修改文件,可以使用参数--write和--install。
npx babel-upgrade --write --install
我们引入了babel.config.js。
*.js配置文件在JavaScript生态系统中相当常见。ESLint和Webpack分别使用了.eslintrc.js和webpack.config.js配置文件。但这并不意味着它们就取代了.babelrc或package.json,这不是必要条件,但在某些情况下这可能很有用。以下是仅在“生产”环境中使用插件进行编译的配置。
var env = process.env.NODE_ENV;
module.exports = {
plugins: [
env === "production" && "babel-plugin-that-is-cool"
].filter(Boolean)
};
babel.config.js的配置解析方式与.babelrc不同。它始终会解析该文件中的配置,而不会从每个文件向上查找,直到找到配置为止。这样就可以利用overrides特性。
module.exports = {
presets: [
// defeault config...
],
overrides: [{
test: ["./node_modules"],
presets: [
// config for node_modules
],
}, {
test: ["./tests"],
presets: [
// config for tests
],
}]
};
有些应用程序需要针对测试、客户端代码和服务器代码使用不同的编译配置选项,通过这种方式就不需要在每个文件夹下创建.babelrc文件了。
我们做了很多变更来优化代码,并接受了来自V8团队的一些补丁(https://twitter.com/rauchg/status/924349334346276864)。
Babel支持预设和插件选项有一段时间了。比如,你可以将插件包装在一个数组中,并将选项对象传给插件:
//减号表示移除,加号表示增加:
{
"plugins": [
- "pluginA",
+ ["pluginA", {
+ // options here
+ }],
]
}
我们对部分插件的loose选项做了一些修改,并为部分插件添加了一些新选项!
比如,对于类class A {},现在不包含_classCallCheck。
class A {}
-------------------
//减号表示移除:
var A = function A() {
- _classCallCheck(this, A);
};
如果for-of循环的是一个数组,那么可以使用这个新选项:[“transform-for-of”,{“assumeArray”:true}]
let elm;
for (elm of array) {
console.log(elm);
}
----------------------
let elm;
for (let _i = 0, _array = array; _i < _array.length; _i++) {
elm = _array[_i];
console.log(elm);
}
在loose模式下将transform-typeof-symbol插件排除在外。
转换后的ES6类使用/#PURE/进行注解,这样就可以告诉Uglify和babel-minify移除死代码。这些注解也被添加到其他辅助函数中。
class C {
m() {}
}
---------------------
var C =
/*#__PURE__*/
function () {
// ...
}();
以下是Babel支持的一些新语法以及已经添加到v7中的语法清单:
ES2018:Object Rest Spread (var a = { b, ...c })
ES2018(新):Unicode属性正则表达式
ES2018(新):JSON超集
ES2015(新):new.target
阶段3(新):类私有实例字段(class A { #b = 2 })
阶段3(WIP):静态类字段、私有静态方法(class A { static #a() {} })
阶段3(新):可选Catch绑定try { throw 0 } catch { do() }
第3阶段(新):BigInt(仅限语法)
第3阶段:动态导入(import("a"))
第2阶段(新):import.meta(仅限语法)(import.meta.url)
第2阶段(新):数字分隔器(1_000)
第2阶段(新):function.sent
第2阶段:export-namespace-from(export * as ns from'mod'),从export-extensions中拆分出来
第2阶段:装饰器
第1阶段:export-default-from(export v from 'mod'),从export-extensions中拆分出来
第1阶段(新):可选链接(a?.b)
第1阶段(新):逻辑赋值(a &&= b; a ||= b)
第1阶段(新):Nullish Coalescing(a ?? b)
第1阶段(新):管道操作符(a |> b)
第1阶段(新):throw表达式(() => throw new Error("a"))
我们与TypeScript团队合作,让Babel使用@babel/preset-typescript解析/转换类型语法,类似于我们使用@babel/preset-flow处理Flow的方式。
之前(有类型):
interface Person {
firstName: string;
lastName: string;
}
function greeter(person : Person) {
return "Hello, " + person.firstName + " " + person.lastName;
}
之后(移除了类型):
function greeter(person) {
return "Hello, " + person.firstName + " " + person.lastName;
}
正如React博客中所提到的,从Beta.31开始,已经支持JSX Fragment。
render() {
return (
<>
<ChildA />
<ChildB />
</>
);
}
-----------------------
// output
render() {
return React.createElement(
React.Fragment,
null,
React.createElement(ChildA, null),
React.createElement(ChildB, null)
);
}
@babel/runtime已经被分为@babel/runtime和@babel/runtime-corejs2。前者仅包含Babel的辅助函数,后者包含辅助函数以及polyfill函数(例如Symbol、Promise)。
规范规定了需要通过new Person()实例化一个类,但如果它被编译成一个函数,就可以直接调用Person(),所以我们提供了一个运行时检查。
class Person {}
------------------------
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Person = function Person() {
_classCallCheck(this, Person);
};
使用@babel/plugin-transform-runtime和@babel/runtime(作为依赖项),Babel可以提取单个函数,而且只需要模块函数来获得较小的输出,如下所示:
var _classCallCheck = require("@babel/runtime/helpers/classCallCheck");
var Person = function Person() {
_classCallCheck(this, Person);
};
要使用polyfill,只需导入@babel/polyfill即可:
import "@babel/polyfill";
但这样会导入整个polyfill,如果浏览器已经支持某些特性,就不需要导入所有内容。我们可以使用选项useBuiltins:”entry”来导入需要用到的部分。
我们可以更进一步,通过选项useBuiltIns:”usage”只将需要用到的polyfill导入到代码库中。
它将遍历每个文件,并在每个使用了内置polyfill的文件的顶部注入一个导入语句。例如:
import "core-js/modules/es6.promise";
var a = new Promise();
但它的推理不是很完美,可能会出现误报:
import "core-js/modules/es7.array.includes";
a.includes // assume a is an []
Babel的一大特点是它的可插拔性。多年来,Babel从一个“6to5”编译器转变为代码转换平台,为用户和开发人员提供了出色的优化选项。人们已经为特定库和用例开发了大量的Babel插件,用以提升库API的性能和功能。
可惜的是,将这些插件添加到代码库中需要更改配置,从而增加了代码复杂性。由Kent C. Dodds开发的babel-plugin-macros(https://github.com/kentcdodds/babel-plugin-macros)已经解决了这个!
在安装了babel-plugin-macros并将其添加到配置中(它已包含在create-react-app v2中)之后,你就不必费心配置就可以使用宏了。此外,为特定应用程序或代码编写自定义转换也变得更加容易。
Babel一直试图在转换的影响范围和功能之间做出平衡。在Babel 7中,通过配置Babel来支持模块/非模块模式变得更加容易。
值得注意的是,一些流行的Web框架的CLI工具已经在利用这些支持,这让转换后的JavaScript代码减少了大约20%。
Babel总是会警告说它不支持扩展原生内置元素(Array、Error等),但现在可以了!我们对类插件进行了修改,如果你使用了preset-env,那么默认就自动启用了这个特性。
我们将我们的网站从Jekyll(https://jekyllrb.com/)搬到了Docusaurus(https://docusaurus.io/)!
我们将REPL重写为React组件,并更好地与CodeSandbox集成。这样你就可以在REPL中安装来自npm的任何插件或预设,并获取CodeSandbox的任何更新。
有一天,Angus给我们传了一首很棒的歌,于是我们就把它作为我们的“主题歌”?Shawn还制作了一张很精彩的封面(https://www.youtube.com/watch?v=40abpedBKK8)。
这首歌可以在代码库的SONG.md(https://github.com/babel/babel/blob/master/SONG.md)中找到。
Babel本质上就是要与JavaScript紧紧联系在一起,包括在语法变得“稳定”之前花时间和精力来实现和维护语法。我们关心的是整个过程:升级路径、新特性的传播、标准/语言设计的教学、易用性以及与其他项目的集成。
在Nicolò的帮助下,我们几乎完成了新的装饰器的实现。这是一个漫长的旅程(我们已经花了一年多的时间!),因为新的提案完全不同,而且比旧的更强大。它可能会在下一个次要版本中发布。
还有很多新特性还在开发当中:插件顺序、更好的验证/错误、速度提升、新的loose/spec选项、缓存、异步使用Babel、从CI构建、冒烟测试、运行test262。
如果我们有足够的时间和资源来完成所有这些想法并且做得好,那就太好了。但正如我们在当前版本中所展示的那样,完整这些工作需要比预期更长的时间!或许是因为我们对自己设定了太高的期望。但不管怎样,努力实现这一版本是非常值得的。