1. 程式人生 > 實用技巧 >babel polyfill 的一些理解

babel polyfill 的一些理解

前言

為了支援業務中少量的es6+的高階特性,最近在研究了一下babel的墊片,現將此整理為文字,如下。

babel 和 babel ployfill 的關係

1、先來理解下 babel 到底是做什麼的?

簡單來講,babel解決語法層面的問題。用於將ES6+的高階語法轉為ES5。

2、babel polyfill 又是做什麼的?

如果要解決API層面的問題,需要使用墊片。比如常見的有babel-polyfill、babel-runtime和babel-plugin-transform-runtime。

理清了他們之間的關係,那麼再正式來講講有關polyfill的二三事。

polyfill 種類

babel polyfill 有三種

* babel-polyfill
* babel-runtime
* babel-plugin-transform-runtime

babel-polyfill

babel-polyfill通過向全域性物件和內建物件的prototype上新增方法來實現的。所以這會造成全域性空間汙染

babel-polyfill使用的兩種方式

1、webpack.config.js中:
配置webpack.config.js裡的entry設定為entry: ['babel-polyfill',path.join(__dirname, 'index.js')]

2、業務 js 中:
在webpack.config.js配置的主入口index.js檔案的最頂層鍵入

import'babel-polyfill'

兩者打印出來的大小都是一樣的,打包後大小是280KB,如果沒有使用babel-polyfill,大小是3.43kb。兩則相差大概81.6倍。原因是webpack把babel-polyfill整體全部都打包進去了。而babel-polyfill肯定也實現了所有ES6新API的墊片,檔案一定不會小。

那麼有沒有一種辦法,根據實際程式碼中用到的ES6新增API ,來使用對應的墊片,而不是全部載入進去呢?
是的,有的。那就是babel-runtime&babel-plugin-transform-runtime,他們可以實現按需載入。

babel-runtime

簡單說 babel-runtime 更像是一種按需載入的實現,比如你哪裡需要使用 Promise,只要在這個檔案頭部

importPromisefrom'babel-runtime/core-js/promise'

就行了。

不過如果你許多檔案都要使用 Promise,難道每個檔案都要import一下嗎?當然不是,Babel 官方已考慮這種情況,只需要使用babel-plugin-transform-runtime就可以解決手動import的苦惱了。

babel-plugin-transform-runtime

babel-plugin-transform-runtime裝了就不需要裝babel-runtime了,因為前者依賴後者。
總的來說,babel-plugin-transform-runtime就是可以在我們使用新 API 時自動 import babel-runtime 裡面的 polyfill,具體外掛做了以下三件事情:

  • 當我們使用 async/await 時,自動引入 babel-runtime/regenerator
  • 當我們使用 ES6 的靜態事件或內建物件時,自動引入 babel-runtime/core-js
  • 移除內聯 babel helpers 並替換使用 babel-runtime/helpers 來替換

babel-plugin-transform-runtime優點:

  • 不會汙染全域性變數
  • 多次使用只會打包一次
  • 依賴統一按需引入,無重複引入,無多餘引入
  • 避免 babel 編譯的工具函式在每個模組裡重複出現,減小庫和工具包的體積

使用方式

在 .babelrc 中配置:

plugins:\["tranform-runtime"\]

打包後大小為17.4kb,比之前的280kb要小很多。

資源搜尋網站大全 https://www.renrenfan.com.cn

Plugin 外掛

1、官方 Presets

如果不想自己設定一堆外掛的話,官方有env,react,flow三個 Presets。即預安裝了 plugins 的配置。

presets 屬性告訴 Babel 要轉換的原始碼使用了哪些新的語法特性, presets 是一組 Plugins 的集合。如:
babel-preset-es2015: 可以將es6的程式碼編譯成es5
babel-preset-es2016: 可以將es7的程式碼編譯為es6
babel-preset-es2017: 可以將es8的程式碼編譯為es7
babel-preset-latest: 支援現有所有ECMAScript版本的新特性

當我們需要轉換es6語法時,可以在 .babelrc 的 plugins 中按需引入一下外掛,比如:check-es2015-constants、es2015-arrow-functions、es2015-block-scoped-functions等等幾十個不同作用的 plugin。.babelrc中配置項可能是如下方式:

{
  "plugins": \[
    "check-es2015-constants",
    "es2015-arrow-functions",
    "es2015-block-scoped-functions",
    // ...
  \]
}

但 Babel 團隊為了方便,將同屬 ES2015 的幾十個 Transform Plugins 集合到babel-preset-es2015一個 Preset 中,這樣我們只需要在.babelrc的 presets 加入 ES2015 一個配置就可以完成全部 ES2015 語法的支援了。.babelrc中配置如下:

{
  "presets": \[
    "es2015"
  \]
}

2、Stage-X(試驗性 Presets)

這個比較好理解,就是為了支援 TC39 對於草案階段的 ES 最新特性而開發的 presets。

  • Stage 0 - 草稿:只是一個設想可能是一個 Babel 外掛
  • Stage 1 - 提案:值得去推進的東西
  • Stage 2 - 草案:初始化規範
  • Stage 3 - 候選:完整規範和初始化瀏覽器實現
  • Stage 4 - 完成:會加入到下一版中

3、轉換外掛

官方和民間提供了很多的轉換外掛,用於指定對某一項 ES 高階特性進行轉換。
官方見:https://babeljs.io/docs/en/pl...

4、語法外掛

這種外掛可以讓Babel來解析特殊型別的語法。

{
  "parserOpts": {
    "plugins": \["jsx", "flow"\]
  }
}

5、外掛開發

見文件:https://github.com/jamiebuild...

開發採用了 AST 抽象語法樹,類似於 Eslint 外掛開發。

export default function () {
  return {
    visitor: {
      Identifier(path) {
        const name = path.node.name;
        // reverse the name: JavaScript -> tpircSavaJ
        path.node.name = name.split("").reverse().join("");
      }
    }
  };
}

webpack 中使用 babel 二三事

babel 用途是語法轉換,所以webpack 中需要用到babel-loader。而babel-core是 Babel 編譯器的核心,因此也就意味著如果我們需要使用babel-loader進行 es6 轉碼的話,我們首先需要安裝babel-core。

總結

使用場景建議:

  • 開發應用建議使用babel-polyfill 會在全域性新增對應方法
  • 開發框架建議 babel-plugin-transform-runtime 區域性變數 不會汙染全域性,區域性使用es6的函式或方法