@babel/plugin-transform-runtime(二)
部落格:姜瑞濤的官方網站
原文連結:https://www.jiangruitao.com/docs/babel/deep/babel-plugin-transform-runtime-2/
版權採用《署名-非商業性使用-禁止演繹 4.0 國際》許可協議 轉載需註明原文作者、連結與版權協議
@babel/plugin-transform-runtime有三大作用:
1.自動移除語法轉換後內聯的輔助函式(inline Babel helpers),使用@babel/runtime/helpers裡的輔助函式來替代;
2.當代碼裡使用了core-js的API,自動引入@babel/runtime-corejs3/core-js-stable/,以此來替代全域性引入的core-js/stable;
3.當代碼裡使用了Generator/async函式,自動引入@babel/runtime/regenerator,以此來替代全域性引入的regenerator-runtime/runtime;
其中作用1已經在上一節講過,這一節我們著重來學習作用2和作用3。
作用2和3其實是在做API轉換,對內建物件進行重新命名,以防止汙染全域性環境。
在babel-polyfill一節,我們學習了引入'babel-polyfill'或'core-js/stable與regenerator-runtime/runtime'來做全域性的API補齊。但這樣可能有一個問題,那就是對執行環境產生了汙染。例如Promise,我們的polyfill是對瀏覽器的全域性物件進行了重新賦值,我們重寫了Promise及其原型鏈。
有時候我們不想改變或補齊瀏覽器的window.Promise,那麼我們就不能使用'babel-polyfill'或'core-js/stable與regenerator-runtime/runtime',因為其會對瀏覽器環境產生汙染(即修改了瀏覽器的window.Promise)。
這個時候我們就可以使用@babel/plugin-transform-runtime,它可以對我們程式碼裡ES6的API進行轉換。還是以Promise舉例子。
Babel轉換前的程式碼
var obj = Promise.resolve();
若使用了'babel-polyfill'或'core-js/stable與regenerator-runtime/runtime'來做全域性的API補齊,那麼Babel轉換後的程式碼仍然是
var obj = Promise.resolve();
polyfill只是補齊了瀏覽器的window.Promise物件。
若我們不使用polyfill,而開啟@babel/plugin-transform-runtime的API轉換功能。那麼Babel轉換後的程式碼將是
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _promise = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/promise"));
var obj = _promise["default"].resolve();
看到效果了沒?@babel/plugin-transform-runtime把我們程式碼裡的Promise變成了_promise["default"],而_promise["default"]擁有ES標準裡Promise所有的功能。現在,即使瀏覽器沒有Promise,我們的程式碼也能正常執行。
開啟core-js相關API轉換功能的Babel配置與安裝的npm包如下
配套程式碼是github倉庫 https://github.com/jruit/babel-tutorial 的babel14例子
{
"presets": [
"@babel/env"
],
"plugins": [
["@babel/plugin-transform-runtime", {
"corejs": 3
}]
]
}
npm install --save @babel/runtime-corejs3
npm install --save-dev @babel/cli @babel/core @babel/preset-env @babel/plugin-transform-runtime
那麼,上面講的API轉換有什麼用,明明通過polyfill補齊API的方式也可以使程式碼在瀏覽器正常執行?
其實,API轉換主要是給開發JS庫或npm包等的人用的,我們的前端工程一般仍然使用polyfill補齊API。
可以想象,如果開發JS庫的人使用polyfill補齊API,我們前端工程也使用polyfill補齊API,但JS庫的polyfill版本或內容與我們前端工程的不一致,那麼我們引入該JS庫後很可能會導致我們的前端工程出問題。所以,開發JS庫或npm包等的人會用到API轉換功能。
當然,我們前端工程開發的時候也是可以使用@babel/plugin-transform-runtime的API轉換功能,畢竟沒有汙染全域性環境,不會有任何衝突。@babel/plugin-transform-runtime的預設設定下,就是對generators/async開啟了API轉換功能。
細心的你可能已經發現了,我們安裝npm包的時候,安裝的是@babel/runtime-corejs3,而上一節我們安裝的是@babel/runtime。
看名字挺像的,那麼這兩者有什麼不同呢?
在我們不需要開啟core-js相關API轉換功能的時候,我們只需要安裝@babel/runtime就可以了。上一節我們已經知道,@babel/runtime裡存放的是Babel做語法轉換的輔助函式。
在我們需要開啟core-js相關API轉換功能的時候,就需要安裝@babel/runtime的進化版@babel/runtime-corejs3。這個npm包裡除了包含Babel做語法轉換的輔助函式,也包含了core-js的API轉換函式。
除了這兩個包,還有一個@babel/runtime-corejs2的包。它和@babel/runtime-corejs3的功能是一樣的,只是裡面的函式是針對core-js2版本的。
上面的例子主要是拿Promise來講的,它屬於作用2,即對core-js的API進行轉換。其實理解了作用2,也就理解了作用3。
下面簡單說一下作用3。
在之前章節,若我們轉碼前程式碼裡有Generator函式或async函式,轉碼後需要引入'regenerator-runtime/runtime'做全域性API補齊。
全域性API補齊必然會對瀏覽器的window物件進行修改,如果我們不想要汙染window,那麼我們就不能引入'regenerator-runtime/runtime'了。
這個時候,我們可以開啟@babel/plugin-transform-runtime的作用3,對Generator/async進行API轉換。
需要注意的是,@babel/plugin-transform-runtime對Generator/async進行API轉換功能,預設是開啟的,不需要我們設定。
如何開啟或關閉@babel/plugin-transform-runtime的某個功能,除了與安裝的npm包有關,也與Babel配置檔案的配置有關,我們下一節來講。
注:
1.如果我們使用@babel/plugin-transform-runtime來做polyfill的事情,那麼就不要再使用之前講過的polyfill方式了,無論是單獨引入還是@babel/preset-env的方式。因為我們用transform-runtime來做api轉換的目的是不汙染全域性作用域。