日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯(lián)網營銷解決方案
你可能并沒有理解的Babel配置的原理

babel 是一個 JS、TS 的編譯器,它能把新語法寫的代碼轉換成目標環(huán)境支持的語法的代碼,并且對目標環(huán)境不支持的 api 自動 polyfill。

福海ssl適用于網站、小程序/APP、API接口等需要進行數(shù)據(jù)傳輸應用場景,ssl證書未來市場廣闊!成為創(chuàng)新互聯(lián)建站的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:13518219792(備注:SSL證書合作)期待與您的合作!

babel 基本每個項目都用,大家可能對 @babel/preset-env 和 @babel/plugin-transform-runtime 都很熟悉了,但是你真的理解它們么?

相信很多同學只是知道它能干什么,但不知道它是怎么實現(xiàn)的,這篇文章我們就來深入下它們的實現(xiàn)原理吧。

首先,我們先來試一下 preset-env 和 plugin-transform-runtime 的功能:

功能測試

@babel/preset-env 的作用是根據(jù) targets 的配置引入對應插件來實現(xiàn)編譯和 polyfill。

比如這段代碼:

class Dong {
}

在低版本瀏覽器不支持,會做語法轉換。

我們把 targets 指定成比較低版本的瀏覽器,比如 chrome 30,并且打開 debug 選項,它的作用是會打印用到的 plugin。

{
presets: [
['@babel/preset-env', {
targets: 'chrome 30',
debug: true,
useBuiltIns: 'usage',
corejs: 3
}]
]
}

執(zhí)行 babel 就會發(fā)現(xiàn)它用到了這些插件:

這就是 @babel/preset-env 的意義,自動根據(jù) targets 來引入需要的插件,不然要是手動寫這么一堆插件不得麻煩死。

開啟 polyfill 功能要指定它的引入方式,也就是 useBuiltIns。設置為 usage 是在每個模塊引入用到的,設置為 entry 是統(tǒng)一在入口處引入 targets 需要的。

polyfill 的實現(xiàn)就是 core-js,需要再指定下 corejs 版本,一般是指定 3,這個會 polyfill 實例方法,而 corejs2 不會。

上面一段代碼會轉換成這樣:

注入了 3 個 helper,也就是 _createClass 這種以下劃線開頭的輔助方法。

因為 helper 方法里用到了 Object.defineProperty 的 api,這里也會從 core-js 里引入。

我們再測試一下這樣一段代碼:

async function func() {
}

會被轉換成這樣:

除了注入 core-js、helper 代碼外,還注入了 regenerator 代碼,這個是 async await 的實現(xiàn)。

綜上,babel runtime 包含的代碼就 core-js、helper、regenerator 這三種。

@babel/preset-env 的處理方式是 helper 代碼直接注入、regenerator、core-js 代碼全局引入。

這樣就會導致多個模塊重復注入同樣的代碼,會污染全局環(huán)境。

解決這個問題就要使用 @babel/plugin-transform-runtime 插件了。

我們在配置文件里引入這個插件:

{
presets: [
['@babel/preset-env', {
targets: 'chrome 30',
debug: true,
useBuiltIns: 'usage',
corejs: 3
}]
],
plugins: [
['@babel/plugin-transform-runtime', {
corejs: 3
}]
]
}

注意,這個插件也是處理 polyfill ,也就同樣需要指定 corejs 的版本。

然后測試下引入之后有什么變化:

先測試 class 那個案例:

之前是這樣的:

現(xiàn)在變成了這樣:

變成了從 @babel/runtime-corejs3 引入的形式,這樣就不會多個模塊重復注入同樣的實現(xiàn)代碼了,而且 core-js 的 api 也不是全局引入了,變成了模塊化引入。

這樣就解決了 corejs 的重復注入和全局引入 polyfill 的兩個問題。

再測試 async function 那個案例:

之前是這樣的:

同樣有全局引入和重復注入的問題。

引入 transform-runtime 插件之后是這樣的:

也是同樣的方式解決了那兩個問題。

再來測試一個 api 的,用這樣一段代碼:

new WeakMap();

當只配置 preset-env 時:

{
presets: [
['@babel/preset-env', {
targets: 'chrome 30',
debug: true,
useBuiltIns: 'usage',
corejs: 3
}]
]
}

結果是這樣的:

再加上 @babel/plugin-transform-runtime 后:

{
presets: [
['@babel/preset-env', {
targets: 'chrome 30',
debug: true,
useBuiltIns: 'usage',
corejs: 3
}]
],
plugins: [
['@babel/plugin-transform-runtime',
{
corejs: 3
}
]
]
}

結果是這樣的:

這樣我們就清楚了 @babel/plugin-transform-runtime 的功能,把注入的代碼和 core-js 全局引入的代碼轉換成從 @babel/runtime-corejs3 中引入的形式。

@babel/runtime-corejs3 就包含了 helpers、core-js、regenerator 這 3 部分。

功能我們都清楚了,那它們是怎么實現(xiàn)的呢?

實現(xiàn)原理

preset-env 的原理之前講過,就是根據(jù) targets 的配置查詢內部的 @babe/compat-data 的數(shù)據(jù)庫,過濾出目標環(huán)境不支持的語法和 api,引入對應的轉換插件。

targets 使用 browserslist 來解析成具體的瀏覽器和版本:

然后根據(jù) @babel/compact-data 的數(shù)據(jù)來過濾出這些瀏覽器支持的語法和 api:

然后去掉這些已經支持的語法和 api 對應的插件,剩下的就是需要用的轉換插件:

這就是 preset-env 的根據(jù) targtes 來按需轉換語法和 polyfill 的原理。

那 @babel/plugin-transform-runtime 呢?它是怎么實現(xiàn)的?

這個插件的原理是因為 babel 插件和 preset 生效的順序是這樣的(下面是官網文檔的截圖):

先插件后 preset,插件從左往右,preset 從右往左。

這就導致了 @babel/plugin-transform-runtime 是在 @babel/preset-env 之前調用的,提前做了 api 的轉換,那到了 @babel/preset-env 就沒什么可轉了,也就實現(xiàn)了 polyfill 的抽取。

它的源碼是這樣的:

會根據(jù)配置來引入 corejs、regenerator 的轉換插件,實現(xiàn) polyfill 注入的功能。

并且還設置了一個 helperGenerator 的函數(shù)到全局上下文 file,這樣后面 @babel/preset-env 就可以用它來生成 helper 代碼。那自然也就是抽離的了。

這就是 @babel/plugin-transform-runtime 的原理:

因為插件在 preset 之前調用,所以可以提前把 polyfill 轉換了,而且注入了 helpGenerator 來修改 @babel/preset-env 生成 helper 代碼的行為。

原理我們理清了,但是大家有沒有發(fā)現(xiàn)其中的問題:

現(xiàn)有方案的問題

我們通過 @babel/plugin-transform-runtime 提前把 polyfill 轉換了,但是這個插件里沒有 targets 的設置呀,不是按需轉換的,那就會多做一些沒必要的轉換。

這個其實是已知問題,可以在 babel 的項目里找到這個 issue:

當然官方也提出了解決的方案,只不過這個得等 babel 新版本更新再用了,等 babel8 吧。

總結

babel7 以后,我們只需要使用 @babel/preset-env,指定目標環(huán)境的 targets,babel 就會根據(jù)內部的兼容性數(shù)據(jù)庫查詢出該環(huán)境不支持的語法和 api,進行對應插件的引入,從而實現(xiàn)按需的語法轉換和 polyfill 引入。

但是 @babel/preset-env 轉換用到的一些輔助代碼(helper)是直接注入到模塊里的,沒有做抽離,多個模塊可能會重復注入。并且用到的 polyfill 代碼也是全局引入的,可能污染全局環(huán)境。為了解決這兩個問題我們會使用 @babel/plugin-transform-runtime 插件來把注入的代碼抽離,把全局的引入改為從 @babel/runtime-corejs3 引入的方式。

runtime 包包含 core-js、regenerator、helper 三部分。

@babel/plugin-transform-runtime 能生效的原理是因為插件先于 preset 被調用,提前把那些 api 做了轉換,并且設置了 preset-env 生成 helper 的方式。

但是這個轉換和 preset-env 是獨立的,它沒有 targets 的配置,這就導致了不能按需 polyfill,會進行一些不必要的轉換。這個是已知的 issue,等 babel 版本更新吧。

看到這里,你對 babel 的配置和這些配置的原理是否有更深的理解了呢。


當前題目:你可能并沒有理解的Babel配置的原理
本文網址:http://m.5511xx.com/article/coioegg.html