首頁 > 軟體

babel7按需載入polyfill範例詳解

2023-02-06 06:00:42

babel7

babel7釋出了。

在升級到 Babel 7 時需要注意幾個重大變化:

  • 移除對 Node.js 6 之前版本的支援;
  • 使用帶有作用域的 @babel 名稱空間,以防止與官方 Babel 包混淆;
  • 移除年度預設,替換為 @babel/preset-env;
  • 使用選擇性 TC39 個別提案替換階段提案;
  • TC39 提議外掛現在是 -proposal,而不是 -transform;
  • 為某些面向使用者的包(例如 babel-loader、@babel/cli 等)在 @babel/core 中引入peerDependency。

官方提供了一個工具babel-upgrade,對於老專案,只需要執行:npx babel-upgrade --write --install

具體看 https://github.com/babel/babel-upgrade

useBuiltIns:usage

babel的polyfill總是比較大,會影響一些效能,而且也會有一些沒用的polyfill,怎麼減少polyfill的大小呢?

babel7提供了useBuiltIns的按需載入:usage。

設定中設定useBuiltIns:usage,babel就會自動把所需的polyfill載入進來,不需要手動import polyfill檔案。

設定如:

{
    "presets": [
      "@babel/preset-react",
      ["@babel/env", {
        "targets": {
          "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
        },
        "useBuiltIns": "usage",
        "debug": true
      }]
    ],
    "plugins": ["@babel/transform-runtime"]
  }

babel提供的@babel/env全面替換es2015,stage外掛。(如果用到stage的某些外掛需要自行引入。個人感覺stage用起來太不方便了)。

之前的babel-preset-env/babel-preset-react全都改名為@babel/xxx,如果在babel7你還按之前的寫法,會報錯:

Error: Plugin/Preset files are not allowed to export objects, only functions.

效果

看下useBuiltIns:usage的效果。"debug"選項開到true,可以看到打包的檔案。

我用es6摘抄了一些語法,用來測試編譯:

const a = Object.assign({}, { a: 1 });
console.log(a);
function timeout(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}
async function asyncPrint(value, ms) {
    await timeout(ms);
    console.log(value);
}
let s = Symbol();
typeof s;
class ColorPoint {
    constructor(x, y, color) {
      this.color = color;
    }
    toString() {
      return this.color + ' ' + super.toString(); // 呼叫父類別的toString()
    }
  }
asyncPrint('hello world', 50);
function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
}
var hw = helloWorldGenerator();
console.log(hw.next());

babel編譯之後,可以看到載入的polyfill只載入了 es6.object.assign,es6.promise, es6.symbol,es7.symbol.async-iterator , regenerator-runtime。

babel是怎麼知道我們需要哪些polyfill的?

根據我們填的"targets",babel會去查用到的api,當前的target環境支援什麼不支援什麼,不支援的才加polyfill。

可以看到我們編譯後的檔案已經加了polyfill。

檔案大小和效能都有很多提高。

useBuiltIns:entry

useBuiltIns:entry就沒有那麼智慧了,他會根據target環境載入polyfill,他需要手動import polyfill,不能多次引入。
@babel/preset-env會將把@babel/polyfill根據實際需求打散,只留下必須的。做的只是打散。僅引入有瀏覽器不支援的polyfill。這樣也會提高一些效能,減少編譯後的polyfill檔案大小。

main.js需要引入polyfill。import '@babel/polyfill';
可以看到效果。我只截了部分polyfill依賴。

編譯後的檔案引入了一堆polyfill。

最佳實踐

只用polyfill不是最完美的方案。
polyfill會額外引入一些函數,比如:

因為polyfill沒有babel-runtime的helper函數,在編譯async函數的時候,會引入以上的程式碼asyncGeneratorStep_asyncToGenerator

如果你每個檔案都用到了async,那麼冗餘的程式碼將會很大。

babel-runtime

最佳方案就是在用polyfill的同時,再用babel-runtime。

babel-runtime會把asyncGeneratorStep,_asyncToGenerator等函數require進來。從而減小冗餘。

這得益於babel-runtime的helper函數。

所以最佳的設定是polyfill+babel-runtime。

如果用了react可以加@babel/preset-react。

{
    "presets": [
      "@babel/preset-react",
      ["@babel/env", {
        "targets": {
          "browsers": ["last 2 versions", "ie 11"]
        },
        "useBuiltIns": "usage"
      }]
    ],
    "plugins": ["@babel/transform-runtime"]
  }

可以看到,_asyncToGenerator2已被require。

以上就是babel7按需載入polyfill範例詳解的詳細內容,更多關於babel7按需載入polyfill的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com