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

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

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

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

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

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

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

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

功能測試

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

比如這段代碼:

class Dong {
}

在低版本瀏覽器不支持,會(huì)做語法轉(zhuǎn)換。

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

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

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

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

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

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

上面一段代碼會(huì)轉(zhuǎn)換成這樣:

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

因?yàn)?helper 方法里用到了 Object.defineProperty 的 api,這里也會(huì)從 core-js 里引入。

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

async function func() {
}

會(huì)被轉(zhuǎn)換成這樣:

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

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

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

這樣就會(huì)導(dǎo)致多個(gè)模塊重復(fù)注入同樣的代碼,會(huì)污染全局環(huán)境。

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

我們在配置文件里引入這個(gè)插件:

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

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

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

先測試 class 那個(gè)案例:

之前是這樣的:

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

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

這樣就解決了 corejs 的重復(fù)注入和全局引入 polyfill 的兩個(gè)問題。

再測試 async function 那個(gè)案例:

之前是這樣的:

同樣有全局引入和重復(fù)注入的問題。

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

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

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

new WeakMap();

當(dāng)只配置 preset-env 時(shí):

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

結(jié)果是這樣的:

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

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

結(jié)果是這樣的:

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

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

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

實(shí)現(xiàn)原理

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

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

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

然后去掉這些已經(jīng)支持的語法和 api 對應(yīng)的插件,剩下的就是需要用的轉(zhuǎn)換插件:

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

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

這個(gè)插件的原理是因?yàn)?babel 插件和 preset 生效的順序是這樣的(下面是官網(wǎng)文檔的截圖):

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

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

它的源碼是這樣的:

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

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

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

因?yàn)椴寮?preset 之前調(diào)用,所以可以提前把 polyfill 轉(zhuǎn)換了,而且注入了 helpGenerator 來修改 @babel/preset-env 生成 helper 代碼的行為。

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

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

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

這個(gè)其實(shí)是已知問題,可以在 babel 的項(xiàng)目里找到這個(gè) issue:

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

總結(jié)

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

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

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

@babel/plugin-transform-runtime 能生效的原理是因?yàn)椴寮扔?preset 被調(diào)用,提前把那些 api 做了轉(zhuǎn)換,并且設(shè)置了 preset-env 生成 helper 的方式。

但是這個(gè)轉(zhuǎn)換和 preset-env 是獨(dú)立的,它沒有 targets 的配置,這就導(dǎo)致了不能按需 polyfill,會(huì)進(jìn)行一些不必要的轉(zhuǎn)換。這個(gè)是已知的 issue,等 babel 版本更新吧。

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


網(wǎng)頁標(biāo)題:你可能并沒有理解的Babel配置的原理
轉(zhuǎn)載來源:http://m.5511xx.com/article/coioegg.html