[譯]babel版本7.7.0功能更新

[譯]babel版本7.7.0功能更新javascript

7.7.0發佈:錯誤恢復和TypeScript 3.7

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。

解析器錯誤恢復(#10363

像許多其餘JavaScript解析器同樣,@babel/parser每當遇到某些無效語法時,都會引起錯誤。這種行爲對於Babel來講效果很好,由於要將JavaScript程序轉換爲另外一個程序,咱們必須首先確保輸入有效。

鑑於Babel的流行,還有許多其餘工具依賴@babel/parser:首先是babel-eslint 和 Prettier。對於這兩種工具,在出現第一個錯誤時沒法使用時都不理想。

考慮如下代碼,因爲重複__proto__屬性,該代碼無效:

let a = {
  __proto__: x,
  __proto__: y
}

let a = 2;

ESLint和Prettier當前的工做流程以下:

  1. Prettier沒法格式化文件
  2. ESLint報告Redefinition of __proto__ property解析器錯誤
  3. 您刪除第二個__proto__屬性
  4. Prettier沒法格式化文件
  5. ESLint報告Identifier 'a' has already been declared錯誤
  6. 您刪除第二個let關鍵字
  7. Prettier 格式化文件格式

若是它更像這樣會更好嗎?

  1. Prettier格式化文件格式
  2. ESLint報告兩個錯誤:Redefinition of __proto__ propertyIdentifier 'a' has already been declared
  3. 您刪除第二個__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仍然能夠拋出,由於並不是每一個錯誤當前均可以恢復。咱們將繼續改善這些狀況!

新的配置文件擴展名(#10501#10599

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(#10543#10545

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中傳播(#10572

在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 }]
  ]
}

內存使用率改進(#10480

從一開始,咱們就一直在努力(#433#3475#7028等)來提升性能。Babel 7.7.0如今使用的內存減小了20%,與7.6.0相比,轉換大型文件的速度提升了8%。

爲了得到這些結果,咱們優化了在生存期NodePath對象(用於包裝每一個AST節點)中完成的不一樣操做:

  1. 如今咱們避免初始化一些不多使用的對象屬性,直到須要它們爲止,這使咱們避免Object.create(null)爲幾乎每一個AST節點分配資源。
  2. 經過用bookkeeping替換一些不常見的屬性,從而@babel/traverse能夠跳過更新它們,咱們減小了每次訪問單個節點的工做量。
  3. 咱們經過將表示節點遍歷(即,跳過,中止或刪除)的狀態的幾個布爾屬性壓縮到位數組中來優化內存使用。

全部這些改進加起來在轉換性能和內存使用方面存在如下差別:

您也能夠檢出上面圖表的原始數據。若是您想了解更多有關此主題的信息,則能夠閱讀Jùnliàng關於他爲得到這些改進所作的更改的詳細文章

相關文章
相關標籤/搜索