[译]babel版本7.7.0功能更新javascript
2019年11月5日html
今天咱们将发布Babel 7.7.0!java
此版本包括新的分析器功能,如顶级的await( await x(),第3阶段)和Flow enum声明(Flow的建议)。如今,@babel/parser能够选择从某些语法错误中恢复!node
咱们还增长了对TypeScript 3.7的支持:Babel能够解析和转换带有类型注释的私有类字段,使用declare关键字定义的公共类字段注释,类型声明函数签名和enum声明中的模板文字。react
babel如今接受了三个新的配置文件:babel.config.json,babel.config.cjs和.babelrc.cjs,它们的行为和babel.config.js和.babelrc.js文件同样。webpack
最后,Babel 7.7.0使用的内存比7.6.0少20%。git
能够在GitHub上阅读整个变动日志。github
await
解析(#10449)顶级await proposal容许您在模块中await promise,就像它们被包装在一个大型异步函数中同样。例如,这对于有条件地加载依赖项或执行应用程序初始化颇有用:web
// Dynamic dependency path const strings = await import(`./i18n/${navigator.language}.mjs`); // Resource initialization const connection = await dbConnector();
@babel/parser自版本7.0.0起,已支持await经过该allowAwaitOutsideFunction选项使用异步功能以外的功能。typescript
版本7.7.0引入了一个新的topLevelAwait解析器插件,该插件有一些主要区别:
await
提案的要求,它仅容许顶层内部模块,而不容许内部脚本。这是必需的,由于基于同步脚本的模块系统(例如CommonJS)没法支持异步依赖关系。sourceType
时间sourceType: "unambiguous"
。请注意,因为await
在脚本中是有效的标识符,所以许多看起来彷佛绝不含糊的构造其实是模棱两可的,Babel会将它们解析为脚本。例如,await -1
能够是一个waiting表达式的waiting -1
,或者是await
和之间的差别1
。若是@babel/parser直接使用,则能够启用topLevelAwait插件:
parser.parse(inputCode, { plugins: ["topLevelAwait"] });
咱们还建立了@babel/plugin-syntax-top-level-await软件包,您能够将其添加到Babel配置中:
// babel.config.js module.exports = { plugins: [ "@babel/plugin-syntax-top-level-await" ] }
请注意,顶层使用await假定为模块捆绑程序中的支持。Babel自己并无进行转换:若是您使用汇总,则能够启用该experimentalTopLevelAwait
选项,而webpack 5支持该experiments.topLevelAwait
选项。
今后版本开始,若是支持,它将自动启用@babel/preset-env。
像许多其余JavaScript解析器同样,@babel/parser每当遇到某些无效语法时,都会引起错误。这种行为对于Babel来讲效果很好,由于要将JavaScript程序转换为另外一个程序,咱们必须首先确保输入有效。
鉴于Babel的流行,还有许多其余工具依赖@babel/parser:首先是babel-eslint 和 Prettier。对于这两种工具,在出现第一个错误时没法使用时都不理想。
考虑如下代码,因为重复__proto__属性,该代码无效:
let a = { __proto__: x, __proto__: y } let a = 2;
ESLint和Prettier当前的工做流程以下:
Redefinition of __proto__ property
解析器错误__proto__
属性Identifier 'a' has already been declared
错误let
关键字若是它更像这样会更好吗?
Redefinition of __proto__ property
和Identifier 'a' has already been declared
__proto__
属性和第二个let
关键字在这个版本中,咱们添加一个新的选项@babel/parser:errorRecovery。设置为true时,生成的AST将具备一个errors属性,其中包含全部@babel/parser可以从如下其中恢复的错误:
const input = ` let a = { __proto__: x, __proto__: y } let a = 2; `; parser.parse(input); // Throws "Redefinition of __proto__ property" const ast = parser.parse(input, { errorRecovery: true }); ast.errors == [ SyntaxError: "Redefinition of __proto__ property", SyntaxError: "Identifier 'a' has already been declared", ];
@babel/parser仍然能够抛出,由于并不是每一个错误当前均可以恢复。咱们将继续改善这些状况!
Babel 6仅支持一个配置文件:.babelrc,其内容必须使用JSON指定。
Babel 7更改了.babelrcs 的含义,并引入了两个新的配置文件:babel.config.js和.babelrc.js(您能够在docs中了解它们之间的区别)。咱们使用JavaScript添加了配置文件,以容许在启用/禁用插件/选项时定义本身的逻辑。
可是,JSON文件的一大好处是更易于缓存。两次调用时,同一个JavaScript文件能够产生不一样的值,而JSON文件能够保证始终对同一对象求值。此外,JSON配置易于序列化,而没法使用隐式数据或关系序列化JavaScript值(如函数或JavaScript对象)。
请注意,Babel在使用基于JavaScript的配置时也会缓存转换,可是必须评估config文件(以便知道缓存是否仍然有效),并手动配置缓存。
因为这些缘由,Babel 7.7.0引入了对新配置文件的支持:babel.config.json,其行为与相同babel.config.js。
咱们还添加了对两个不一样配置文件的支持:babel.config.cjs和.babelrc.cjs,在中使用node的"type": "module"
选项时必须使用package.json(由于Babel在配置文件中不支持ECMAScript模块)。除了这种"type": "module"差别以外,它们的行为与babel.config.js和彻底相同.babelrc.js。
TypeScript 3.7 RC支持可选的连接,无效的合并运算符,断言函数,类型字段声明以及许多其余与类型相关的功能。
自7.0.0起,经过和都支持Babel中的可选链(a?.b)和无效合并(a ?? b)。@babel/plugin-proposal-optional-chaining和@babel/plugin-proposal-nullish-coalescing-operator
在Babel 7.7.0中,您如今能够在断言函数和declare类字段中使用:
function assertString(x): assert x is string { if (typeof x !== "string") throw new Error("It must be a string!"); } class Developer extends Person { declare usingBabel: boolean; }
为了不重大更改,咱们推出了支持declare在一个标志背后类字段:"allowDeclareFields",双方支持@babel/plugin-transform-typescript和@babel/preset-typescript。这可能会成为默认行为,所以建议您迁移配置以使用它:
{ "presets": [ ["@babel/preset-typescript", { "allowDeclareFields": true }] ] }
在JSX元素中使用传播属性时,Babel默认状况下会注入运行时帮助程序:
<a x {...y} /> // function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } React.createElement("a", _extends({ x: true }, y));
2016年,随着对本地ES6的支持获得改善,咱们添加了一个useBuiltIns选项,@babel/plugin-transform-react-jsx该选项容许编译后的输出直接使用Object.assign并删除多余的代码:
<a x {...y} /> // React.createElement("a", Object.assign({ x: true }, y));
可是,鉴于对对象传播的本地支持,它使咱们可以生成更多优化的代码:
<a x {...y} /> // React.createElement("a", { x: true, ...y });
您可使用或启用该useSpread选项:@babel/preset-react@babel/plugin-transform-react-jsx
{ presets: [ ["@babel/react", { useSpread: true }] ] }
从一开始,咱们就一直在努力(#433,#3475,#7028等)来提升性能。Babel 7.7.0如今使用的内存减小了20%,与7.6.0相比,转换大型文件的速度提升了8%。
为了得到这些结果,咱们优化了在生存期NodePath对象(用于包装每一个AST节点)中完成的不一样操做:
全部这些改进加起来在转换性能和内存使用方面存在如下差别:
您也能够检出上面图表的原始数据。若是您想了解更多有关此主题的信息,则能够阅读Jùnliàng关于他为得到这些改进所作的更改的详细文章!