天天看點

vue - Babel之babel-polyfill、babel-runtime、transform-runtime

引言

babel預設隻轉換新的 JavaScript 文法,比如箭頭函數、擴充運算(spread)。

不轉換新的 API,例如

Iterator

Generator

Set

Maps

Proxy

Reflect

Symbol

Promise

等全局對象,以及一些定義在全局對象上的方法(比如

Object.assign

)都不會轉譯。如果想使用這些新的對象和方法,則需要為目前環境提供一個墊片(polyfill)。

此篇僅對三種polyfill進行介紹,并講了他們的安裝配置。具體的每種對新文法的轉換結果,可以看參考連結的第一個。

三種polyfill介紹

babel-polyfill

目前最常用的配合Babel一起使用的polyfill是babel-polyfill,通過改寫全局prototype的方式實作,它會加載整個polyfill,針對編譯的代碼中新的API進行處理,并且在代碼中插入一些幫助函數,比較适合單獨運作的項目。

babel-polyfill解決了Babel不轉換新API的問題,但是直接在代碼中插入幫助函數,會導緻污染了全局環境,并且不同的代碼檔案中包含重複的代碼,導緻編譯後的代碼體積變大。雖然這對于應用程式或指令行工具來說可能是好事,但如果你的代碼打算釋出為供其他人使用的庫,或你無法完全控制代碼運作的環境,則會成為問題。

babel-runtime

Babel為了解決上述問題,提供了單獨的包babel-runtime用以提供編譯子產品的工具函數,啟用插件babel-plugin-transform-runtime後,Babel就會使用babel-runtime下的工具函數。

babel-runtime插件能夠将這些工具函數的代碼轉換成require語句,指向為對babel-runtime的引用。每當要轉譯一個api時都要手動加上

require('babel-runtime')

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

require Promise from 'babel-runtime/core-js/promise'

就行了

不過如果你許多檔案都要使用 Promise,難道每個檔案都要 import 一遍不成?

babel-plugin-transform-runtime

為了友善使用 babel-runtime,解決手動 require 的苦惱。它會分析我們的 ast 中,是否有引用 babel-rumtime 中的墊片(通過映射關系),如果有,就會在目前子產品頂部插入我們需要的墊片。

transform-runtime 是利用 plugin 自動識别并替換代碼中的新特性,你不需要再引入,隻需要裝好 babel-runtime 和 配好 plugin 就可以了。

好處是按需替換,檢測到你需要哪個,就引入哪個 polyfill,如果隻用了一部分,打包完的檔案體積對比 babel-polyfill 會小很多。而且 transform-runtime 不會污染原生的對象,方法,也不會對其他 polyfill 産生影響。

是以 transform-runtime 的方式更适合開發工具包,庫,一方面是體積夠小,另一方面是使用者(開發者)不會因為引用了我們的工具,包而污染了全局的原生方法,産生副作用,還是應該留給使用者自己去選擇。

⭐比較

babel-polyfill與babel-runtime相比雖然有各種缺點,但在某些情況下仍然不能被babel-runtime替代, 例如,

[1, 2, 3].includes(3)

Object.assign({}

,

{key: 'value'})

Array

Object

以及其他”執行個體”下es6的方法,babel-runtime是無法支援的, 因為babel-runtime隻支援到 static 的方法。

安裝配置

babel-polyfill

因為這是一個 polyfill (它需要在你的源代碼之前運作),我們需要讓它成為一個 dependency,而不是一個 devDependency 。

npm install --save babel-polyfill

直接在代碼中require,或者在webpack的entry中添加,也可以在babel的env中設定useBuildins為true來開啟。

//示例:vue-cli腳手架中使用
import 'babel-polyfill'
           
//示例:webpack的entry中添加
entry: {
    common: [
        `babel-polyfill`,
        `whatwg-fetch`,
        `react`,
        `react-dom`,
        `redux`,
        `react-redux`,
        `js-cookie`,
    ],
},
           

babel-runtime 和 babel-plugin-transform-runtime

在大多數情況下,你應該安裝 babel-plugin-transform-runtime 作為開發依賴(使用 --save-dev),并且将 babel-runtime 作為生産依賴(使用 --save)。這個看vue-cli生成的

package.json

就能發現。

因為babel編譯es6到es5的過程中,babel-plugin-transform-runtime這個插件會自動polyfill es5不支援的特性,這些polyfill包就是在babel-runtime這個包裡(core-js 、regenerator等)

npm install --save-dev babel-plugin-transform-runtime

npm install --save babel-runtime

用法

通過 .babelrc(推薦)

将以下内容添加到你的 .babelrc 檔案中:

未包含選項:

{
  "plugins": ["transform-runtime"]
}
           

包含選項:

{
  "plugins": [
    ["transform-runtime", {
      "helpers": false,
      "polyfill": false,
      "regenerator": true,
      "moduleName": "babel-runtime"
    }]
  ]
}
           

選項

1.輔助(helpers)

預設值是:true

表示是否開啟内聯的babel helpers(即babel或者環境本來的存在的墊片或者某些對象方法函數)(clasCallCheck,extends,etc)在調用子產品名字(moduleName)時将被替換名字。

2.墊片/polyfill

預設值是:`true'

表示是否把内置的東西(Promise,Set,Map,tec)轉換成非全局污染墊片。

3.重新生成/regenerator

預設值是:true

是否開啟generator函數轉換成使用regenerator runtime來避免污染全局域。

4.子產品名字/moduleName

預設值:babel-runtime

當調用輔助(内置墊片)設定子產品(module)名字/路徑.

例子:

{
  "moduleName": "flavortown/runtime"
}
           
import extends from 'flavortown/runtime/helpers/extends';
           

優點

  • 不會污染全局變量
  • 多次使用隻會打包一次
  • 依賴統一按需引入,無重複引入,無多餘引入

缺點

  • 不支援執行個體化的方法,例

    Array.includes(x)

    就不能轉化
  • 如果使用的API用的次數不是很多,那麼transform-runtime 引入polyfill的包會比不是transform-runtime 時大
  • 随着應用的增大,相同的 polyfill 每個子產品都要做重複的工作(檢測,替換),雖然 polyfill 隻是引用,編譯效率不夠高效。

參考連結

Babel用法 | usages transform-runtime

小毛蛋_對babel-transform-runtime,babel-polyfill的一些了解

zackxizi babel-runtime和babel-polyfill的作用介紹和使用

babel-polyfill、babel-runtime 的選擇