[譯]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關於他爲得到這些改進所作的更改的詳細文章!