引言
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 的選擇