Babel之babel-polyfill、babel-runtime、transform-runtime詳解


引言

babel默認只轉換新的 JavaScript 語法,比如箭頭函數、擴展運算(spread)。

不轉換新的 API,例如IteratorGeneratorSetMapsProxyReflectSymbolPromise 等全局對象,以及一些定義在全局對象上的方法(比如 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'})ArrayObject以及其他”實例”下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 的選擇


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM