前言
問題
我們在使用各種打包工具,需要配置Babel
的時候,相信大家一開始都是直接在網上複製貼上一段配置過來,然後能跑通就萬事大吉了吧?因此,我們有時會遇到打包部署後,手機執行出現白屏問題;或者是,打包後程式碼包過大,載入緩慢等等問題。
其實這一切,大部分原因是因為我們對Babel
各項配置沒有一個系統的理解,所以即使從網上覆制貼上了配置,出現問題了,不知道怎麼去分析出現的問題。
準備
如果你已經對Babel
已經有一個大概的瞭解了,那閱讀這篇文章,會讓你對配置有一個更系統的瞭解;如果你才剛接觸Babel
,或者對Babel
處於懵懵懂懂的狀態,那我強烈建議你先閱讀這篇文章——想弄懂Babel?你必須得先弄清楚這幾個包,它主要介紹分析了一些概念跟以下幾個包:
@babel/core
@bable/cli
@bable/preset-env
polyfill
@babel/polyfill
core-js
@babel/runtime
@babel/plugin-transform-runtime
並且為我們答疑了一些看官網時的疑惑。因為在清楚了這幾包後,我們學習配置這塊會更容易理解一些。
備註
- 當前
@babel/core
最新版本是:7.20.12
- 當前
@babel/preset-env
最新版本是:7.20.2
再談core-js
透過上篇文章—— 想弄懂Babel?你必須得先弄清楚這幾個包我們知道:core-js
是一種polyfill
,它提供了舊版本瀏覽器缺失的所有的ES6+
API
的方法與實現。
在這裡,以及下文,我們把透過引入core-js
的某個模組,來實現舊版本瀏覽器不支援的某個ES6+
API
的過程,叫做墊平。
我們看看core-js
這個包裡面的主要一些模組:
es
:裡面只包含有穩定的ES
功能。proposals
:裡面包含所有stage
階段的API
stable
:它裡面包含了,只有穩定的ES
功能跟網路標準
所以,我們可以這麼使用:
- 當我們只需要墊平某個穩定的
ES6+
API
,我們可以用es
這個資料夾裡的polyfill
來墊平 (import X from 'es/xx'
) - 當我們需要用到提案階段的
API
時,我就用proposals
這個資料夾裡的polyfill
來墊平(import X from 'proposals/xx'
) - 當我們想墊平所有穩定版本的
ES6+
API
,可以匯入用stable
資料夾(import 'core-js/stable'
) - 當我們想墊平所有的
ES6+
API
(包括提案階段),可以直接import 'core-js'
以上是我個人的使用習慣,因人而異,具體的介紹可以看看參考文章。
參考文章:core-js
再談@bable/preset-env
透過上篇文章—— 想弄懂Babel?你必須得先弄清楚這幾個包,我們知道:
Babel
大體由兩個功能組成:- 編譯
ES6+
最新語法(let
、class
、() => {}
等) - 實現舊版本瀏覽器不支援的
ES6+
的API
(Promise
、Symbol
、Array.prototype.includes
等)
- 編譯
@babel/preset-env
有以下兩個功能:- 它只編譯
ES6+
語法 - 它並不提供
polyfill
,但是可以透過配置我們程式碼執行的目標環境,從而控制polyfill
的匯入跟語法編譯,使ES6+
的新特性可以在我們想要的目標環境中順利執行
- 它只編譯
@babel/plugin-transform-runtime
也有以下兩個功能:@babel/runtime
跟@babel/plugin-transform-runtime
兩者配合,可以減少打包體積- 也有一個配置功能,用來處理
polyfill
如何墊平
- 如果我們想要在舊瀏覽器用到
ES6+
API
時,我們應該安裝3
版本的core-js
(或者後續更高版本的);
那我們可以很清楚的知道:
- 實現
Babel
第一個功能:我們用@babel/preset-env
就可以了 - 實現
Babel
第二個功能:我們就需要用core-js
這個包來提供polyfill
,並與@babel/preset-env
或者@babel/plugin-transform-runtime
的配置功能相互配合使用
我們先來看看@babel/preset-env
的配置項有哪些:
// babel.config.js
const presets = [
[
'@babel/preset-env',
{
modules,
targets,
corejs,
useBuiltIns,
spec,
loose,
debug,
bugfixes,
include,
exclude,
forceAllTransforms,
configPath,
ignoreBrowserslistConfig,
browserslistEnv,
shippedProposals
}
]
];
module.exports = {presets};
我們可以看到配置項還是蠻多的(有一些配置項,後期可能會廢棄),但是,其實我們平時專案中主要用到前四個配置,所以在這裡我們重點來看看前四個配置(能不學的儘量不學,太累了)。
參考文章:@babel/preset-env
modules
- 功能:啟用
ES
模組語法向另一種模組型別的轉換 - 預設值:
auto
- 可取的值:
"amd" | "umd" | "systemjs" | "commonjs" | "cjs" | "auto" | false
當我們設定成false
的時候,Babel
編譯產生的一些輔助函式的引入方式會變成ES6
的模式引入(import A from 'B'
)。
我們把 use-transform-runtime 這個案例Babel
配置改成以下配置,感受一下modules
這個配置的功能。
// babel.config.js
const plugins = [
'@babel/plugin-transform-runtime'
]
const presets = [
[
'@babel/preset-env',
{
modules: false
}
]
];
module.exports = {plugins, presets};
在沒設定modules
配置項時,編譯後的檔案是:
我們會發現輔助函式都是以require
的方式引入的;
在設定了modules
配置項後,編譯後的檔案是:
我們會發現輔助函式變成了我們熟悉的ES6
模組方式import
引入。
這樣有一個好處,就是我們用一些像Webpack
打包工具時,可以對程式碼靜態分析,很好地tree shaking
減少程式碼體積,所以我們配置Babel
的時候建議設定modules: false
參考文章:modules
targets
作用
它的用法與 browserslist 一致。它可以用來設定我們的程式碼需要相容的目標環境,因此它:
- 可以有效地減少
ES6+
的語法編譯 - 可以有效控制
polyfill
匯入多少
注意
第一點
如果我們沒有設定這個配置項時,它會去我們的Babel
配置檔案找頂層的targets
;如果頂層沒有設定targets
,則會去我們的package.json
裡的browserslist
或者根目錄找.browserslistrc
;如果還沒有則預設值為{}
。查詢過程大致如下,序號代表查詢順序:
// Babel配置檔案
{
targets: 'ie 10', // 2. 如果presets裡面沒有設定targets,會來這裡查詢
presets: [
[
'@babel/preset-env',
{
targets: 'ie 9' // 1. 先在這裡查詢,沒的話去頂層targets查詢
}
]
]
}
// package.json
{
...,
browserslist: [
'ie 11' // 3. 如果頂層targest裡面沒有設定,會來這裡查詢;如果這裡也沒設定,則為預設值{}
]
}
第二點
如果我們沒有設定這個配置項時,Babel
會假設我們要相容的目標環境是最舊的瀏覽器,所以會將所有的ES6+
語法程式碼轉化為ES5
。所以我們配置Babel
的時候,要設定targets
以減少輸出程式碼大小。
針對這點,我們用這個案例 preset-env-targets-config 來感受一下:
我們會發現ES6+
的寫法全部被轉成了ES5
,還加入了一些輔助函式(白色框)。
ok,我們設定targets: 'chrome 80'
。這表示,我們的程式碼是要在chrome 80
上執行的,再看看打包後的結果:
我們會發現編譯出來的程式碼,跟我們入口檔案寫的程式碼基本沒差。因為chrome 80
已經實現了入口檔案程式碼的寫法了。所以,如果我們的程式碼不需要在一些比較低端的瀏覽器跑的話,設定targets
就十分有必要。
參考文章:targets
corejs
當useBuiltIns
不為false
的時候,需要設定這個配置項
配置
它有兩種配置方式:
直接設定
core-js
版本號... { useBuiltIns: 'usage', corejs: '3.27.2' } ...
配置
corejs
... { useBuiltIns: 'usage', corejs: { version: '3.27.2', // 是否編譯提案階段ES6+ API proposals: false }, } ...
注意
- 當我們的
useBuiltIns
不為false
的時候,需要設定corejs
這個配置項 2
版本的core-js
已經不建議使用了;我們用當然要用最新的,目前最新的版本是core-js@3.27.2
- 我們安裝的
core-js
要儘量保持最新,因為越新的包,包含的polyfill
才會越多 - 我們設定
corejs
的版本號時,不要直接指定2
或者3
,它會被解析為2.0
或者3.0
。所以,我們應該帶上子版本號(3.27.2
),這樣才會有最新的polyfill
core-js
預設用穩定版的polyfill
來墊平,但如果有時我們想用還處在提案階段的API
怎麼辦?- 如果我們配置的是
useBuiltIns: entry
,我們得手動引入core-js
提案的polyfill
來墊平。提案的polyfill
放在core-js/proposals
資料夾中(import 'core-js/proposals/array-last'
) - 如果我們配置的是
useBuiltIns: 'usage'
,則我們用上面說的corejs
模組裡面提到的第二種配置方式,把proposals
設為true
就可以了
- 如果我們配置的是
它的作用會結合下面的useBuiltIns
一起講。
參考文章:targets
useBuiltIns
上面我們提到了,我們把透過引入core-js
的某個模組,來實現舊版本瀏覽器不支援的某個ES6+
API
的過程,叫做墊平。
這個配置就是用來設定我們core-js
的墊平方式的。它有下面三個值:
為了更好的理解,我們用
Promise
這個ES6+
API
作為下面的例子。我們都知道:
IE 11
並不支援Promise
Promise
這個物件其實還有很多方法,例如Promise.any
、Promise.all
、Promise.finally
等。- 我們用這個案例 preset-env-useBuiltIns-config 來講解
entry
我們可以這麼理解,entry
中文是“進入”的意思,這個值說明我們的polyfill
應該是需要從某個入口引入來墊平。
表現
我們把配置設定為:useBuiltIns: 'entry'
- 我們先來看看這個配置在
IE 11
的表現形式,我們設定targets: 'ie 11'
:
- 我們再把
targets
設定成chrome: 80
看看錶現:
分析
在
IE 11
的表現我們
import 'core-js/es/promise'
(相當於import
某塊polyfill
來墊平),由於我們的IE 11
不支援Promise
,所以useBuiltIns: 'entry'
配置把我們所有不支援的Promise
方法都墊平了(列印的window.Promise.any
有值)。在
chrome 80
表現我們
import 'core-js/es/promise'
(相當於import
某塊polyfill
來墊平), 因為在chrome 80
中,Promise
大部分方法已經實現,只有Promise.any
沒有實現,所以此時只墊平了promise.any
方法。
總結
所以我們可以總結出,它的執行原理大致是這樣的:
- 我們需要手動
import
所有或者某塊polyfill
Babel
會根據我們設定的targets
(目標環境),來判斷我們手動import
的所有或者某塊polyfill
是不是當前缺失的- 如果是的話,就會把我們手動
import
所有或者某塊polyfill
,拆分成很多小模組,引入我們目標環境不支援的模組
注意
- 為了避免一些奇奇怪怪的問題,我們手動
import
的polyfill
應該統一在入口檔案(我們現在的工程專案一般都會有一個入口檔案) - 如果我們想一勞永逸,直接把當前環境所有不支援的
ES6+
API
墊平,那我們就import 'core-js/stable'
(這會墊平當前targets
不支援的所有穩定版本的ES6+
API
,所以也會導致包變大) - 如果我們只想單純墊平某個
ES6+
API
(前提是targets
不支援這個API
,否則手動import
了也沒用;例如只想墊平Promise
),那我們import 'core-js/es/promise
就可以了 - 如果想墊平提案階段的
API
,則也需要手動import
對應提案的polyfill
(import "core-js/proposals/string-replace-all
)
參考文章:usebuiltins
usage
這個值的作用,就是我們不需要手動import
,它會自動幫我們import
當前targets
缺失的polyfill
。
表現
我們把配置設定為:useBuiltIns: 'usage'
- 我們先來看看這個配置在
IE 11
的表現形式,我們設定targets: 'ie 11'
:
- 我們再把
targets
設定成chrome: 80
看看錶現:
分析
在
IE 11
的表現我們不用自己手動
import
相關polyfill
,我們的程式碼中只用到了單一的Promise
物件,所以只墊平了Promise
這個物件,不會墊平它其他相關的方法(列印的window.Promise.any
無值)。在
chrome 80
的表現我們不用自己手動
import
相關polyfill
,此時沒有任何關於Promise
的墊平,因為單一的Promise
物件在chrome 80
已經實現,且我們程式碼中沒有用Promise.any
方法,自然也就不會墊平Promise.any
。此時程式碼只墊平了提案階段的array.lastItem
方法,因為chrome 80
不支援它,並且我們程式碼中用到了它。
總結
所以我們可以總結出,它的執行原理大致是這樣的:
- 我們不需要手動
import
所有或者某塊polyfill
Babel
會根據我們當前程式碼中用到的ES6+
API
,並判斷當前的targets
支不支援我們用到的這個ES6+
API
- 如果不支援的話,則自動匯入這個
ES6+
API
對應的polyfill
因為它會自動匯入,所以我們專注寫我們的ES6+
就好了。
參考文章:usebuiltins
false
它是預設值。它表示不要在每個檔案中自動新增polyfill
,也不會根據targets
判斷缺不缺失,也不會將我們手動import
所有或者某塊polyfill
拆分為單個polyfill
引入。
表現
我們把配置設定為:useBuiltIns: false
- 我們先來看看這個配置在
IE 11
的表現形式,我們設定targets: 'ie 11'
:
- 我們再把
targets
設定成chrome: 80
看看錶現:
總結
useBuiltIns
設定為false
:
- 對我們的墊平方式沒作用,原始碼是什麼樣,輸出就是什麼樣
- 設定
targets
無效
參考文章:usebuiltins
使用
適配 IE 11
相信透過上面的講解,我們對各個配置項有個大概的瞭解了,那我們再更深入體驗一下。
我們都知道IE 11
基本是不支援ES6+
的,我們抽幾個常用的ES6+
API
看看:
那我們就用IE 11
作為我們的targets
(目標環境),研究一下如何配置Babel
,使我們寫的ES6+
程式碼能在IE 11
中跑起來。我們用這個案例 preset-env-template-config
注意:
為了避免Webpack
打包錯誤,我們把targets
寫在package.json
中,這樣Webpack
才能識別環境打包... "browserslist": [ "ie 11" ] ...
我們用一下這段程式碼作為我們的入口檔案:
// 如果用`usage`方式,則註釋掉這段程式碼
import 'core-js/stable';
const lMC = {
name: 'limingcan',
like: ['eat', 'drink', 'play', 'fun'],
breath() {
return new Promise(resolve => {
setTimeout(() => resolve(), 1000)
})
}
};
lMC.breath().then(() => console.log('breath'));
console.log(lMC.like.includes('play'));
console.log(Array.of(1, 2, 3));
根據我們上面幾個配置項的講解,如果我們想:
一勞永逸的直接墊平
targets
所有不支援的ES6+
API
,那我們的配置應該是:const presets = [ [ '@babel/preset-env', { modules: false, useBuiltIns: 'entry', corejs: { version: '3.27.2', proposals: true } } ] ]; module.exports = { presets};
此時
IE 11
正常輸出:紅色框是我們原始碼中沒用到的
ES6+
API
,也都被墊平了;此時包的大小有115K
如果我們想減少包的體積,只墊平我們用到的
ES6+
API
,那我們的配置應該是:const presets = [ [ '@babel/preset-env', { modules: false, useBuiltIns: 'usage', corejs: { version: '3.27.2', proposals: true } } ] ]; module.exports = { presets};
此時
IE 11
正常輸出:但是我們會發現,紅色框是我們原始碼中沒用到的
ES6+
API
,它並沒有被墊平的,它只會墊平我們程式碼中用到的API
;此時包的大小隻有29K
常見問題
透過上面的例子,我們會發現:
如果配置是useBuiltIns: 'entry'
- 我們墊平的
polyfill
,都是注入到window
全域性的,或者是某個內建物件的原型(prototype
)上,這影響到了全域性 - 一勞永逸的方式會墊平當前
targets
所有不支援的ES6+
API
,這雖然方便,但這會導致包變得很大
如果配置是useBuiltIns: 'usage'
- 它也會將墊平的
polyfill
注入到全域性。 - 由於
useBuiltIns: 'usage'
是判斷當前targets
支不支援我們程式碼中用到的ES6+
API
,如果不支援會自己import
。
那有這樣一種情況,如果第三方庫用到了我們當前targets
不支援的ES6+
API
,但我們自己的程式碼沒有用到這個API
,那麼這個API
是不會被疊平的,這會導致我們專案報錯。
第三方庫問題
針對useBuiltIns: 'usage'
配置的第二點弊端,我們來看這個例子 use-third-party-library-problem 更直接的感受一下。
我們把targets
設為IE 11
,我們自己的程式碼只用includes
這個ES6+
API
,然後再用第三方庫 tars-utils 的optimizeImage
方法,生成一個Blob
物件(裡面是用Promise
實現的)。
我們在IE 11
跑一下看看:
透過Babel
編譯後的檔案,我們會發現:
- 只有我們程式碼中使用的
includes
方法被墊平; - 第三方庫中用到的
Promise
並沒有被墊平,所以導致IE 11
報錯了。這是一個非常現實的問題。
我們在高階一點的瀏覽器(chrome 108
)看看:
在chrome 108
執行沒有任何問題,因為chrome 108
已經內部實現了Promise
。
總結
看到這裡,相信我們對@babel/preset-env
的配置功能已經有個大概的瞭解了。上述所說的問題確實是我們很實際的問題。
因此,useBuiltIns
設定entry
還是usage
,還是得根據我們專案實際需求來,我個人建議:
- 由於我們
@babel/preset-env
配置方式,是會把當前targets
缺失的API
注入到全域性,所以這個配置方式是比較適合我們做的一些前端工程專案或者應用程式。如果對包的體積不是很在意,建議使用useBuiltIns: entry
的方式,然後再import 'core-js/stable'
,一勞永逸的墊平,這樣可以幫我們避免掉一些奇怪的問題, - 如果使用
useBuiltIns: usage
,那還是得注意第三方庫的問題。如果判斷出哪塊polyfill
缺失,我們可以自己手動import
去墊平
再談@babel/plugin-transform-runtime
上面說到,@babel/preset-env
配置方式,是會把當前瀏覽器缺失的API
注入到全域性的,那麼有沒有不注入全域性的辦法呢?答案是有的。它就是我們接下來要講的@babel/plugin-transform-runtime
配置。
我們先來看看它有幾個配置項(謝天謝地,不算很多):
// babel.config.js
const plugins = [
[
'@babel/plugin-transform-runtime',
{
helpers,
regenerator,
corejs,
version
}
]
];
module.exports = {plugins};
helpers
&& regenerator
解析
我們先看前兩個配置,因為前兩個配置比較簡單,我們放在一起講。
helpers
預設值是:true
regenerator
預設值是:true
透過上篇文章——想弄懂Babel?你必須得先弄清楚這幾個包,我們知道:
關於@babel/runtime
@babel/runtime
是存放了Babel
輔助函式的一個集合包
關於輔助函式
- 當我們只用了一些
ES6+
語法糖的時候,Babel
編譯時會內聯注入一些輔助函式 @babel/plugin-transform-runtime
與@babel/runtime
配合使用時,會將我們用到的輔助函式,從@babel/runtime
中以require
或者import
的方式,引入到我們的檔案中,實現複用,從而減小我們最終輸出包的體積。
關於regenerator
- 我們的原始碼裡面使用了
async function() {}
等非同步函式,或者fuction* myGenerator() {}
這種Generator
函式的話,就會需要用到regenerator-runtime
這個包來編譯。 Babel >= 7.18.0
,regenerator-runtime
包裡的內容,會以區域性變數的方式內聯注入到我們的程式碼中,這樣我們就不需要全域性提供一個regeneratorRuntime
物件。
例如我們使用了class
語法糖跟async function() {}
,然後用@babel/runtime
跟@babel/plugin-transform-runtime
(預設情況下,helpers
與regenerator
值為true
)配合使用,編譯後如下圖:
當我們把helpers
跟regenerator
的值設為false
:
我們會發現我們的輔助函式,跟regenerator-runtime
這個包又變回了內聯方式。所以:
helpers
:控制的是我們的輔助函式,是否不內聯進我們的程式碼中。true
的話是不內聯,而是引用@babel/runtime
輔助函式集合包false
的話,則會內聯
regenerator
:與helpers
類似,控制的是我們regenerator-runtime
這個包的程式碼,是否不內聯進我們的程式碼中。true
的話是不內聯,而是引用@babel/runtime
輔助函式集合包false
的話,則會內聯
注意
官網中關於regenerator
的解釋,大致意思是:regenerator
如果設為false
,需要我們提供一個全域性的regeneratorRuntime
的物件。
但是:
- 當
Babel >= 7.18.0
以後,regenerator-runtime
包裡的內容,會以區域性變數的方式內聯注入到我們的程式碼中。所以其實Babel >= 7.18.0
regenerator
這個配置項個人覺得是基本沒用了 Babel < 7.18.0
的話,則需要我們提供一個全域性的regeneratorRuntime
的物件。相關案例可檢視 import-regenerator-runtime,開啟babel.config.js
相關注釋程式碼。
corejs
解析
corejs
這個配置項一旦不為false
,就是用來設定我們的要墊平的ES6+
API
,以不汙染全域性區域性變數方式墊平。
它有三個值:
值 | 對應依賴 | 補充 |
---|---|---|
false (預設值) | @babel/runtime | |
2 | @babel/runtime-corejs2 | 1. 只能編譯支援全域性變數(如Promise )和靜態屬性(如Array.from );<br/>2. 不能編譯例項相關方法([].includes ) |
3 | @babel/runtime-corejs3 | 1. 既能編譯能編譯支援全域性變數和靜態屬性,又能編譯例項方法 2. 開啟 proposals: true ,還可以編譯提案階段的API |
我們用這個例子 transform-runtime-config 體驗一下。
如果配置的是
corejs: 2
的話,會怎麼樣:
我們會發現,例項方法
includes
沒被墊平,提案API
(Math.signbit
)也沒有被墊平;Promise
是以區域性變數的方式出現在我們的程式碼中。- 我們再看看配置的是
corejs: {version: 3, proposals: true}
:
我們會發現,例項方法includes
被墊平,提案API
(Math.signbit
)也墊平;但它們都以區域性變數的方式注入。
所以,如果我們不想以全域性的方式汙染的方式墊平我們的ES6+
API
,我們corejs
就不能為false
,並且優先使用@babel/runtime-corejs3
這個包來墊平(設定為3
)
最佳化
上面的案例我們並沒有設定targets
,所以@babel/plugin-transform-runtime
配置下,會把我們程式碼中用到的所有ES6+
API
都墊平。我們來設定targets
,看看能不能墊平我們的targets
不支援的ES6+
API
。
我們在package.json
裡面新增,或者在配置檔案的頂層新增是可以的(經過測試,在@babel/preset-env
裡面設定targets
是不行的):
// package.json
"browserslist": [
"chrome 80"
]
// 或者在頂層新增
module.exports = {
targets: {chrome: 80}, // 在這裡新增
presets: ['@babel/preset-env'],
plugins: [
[
"@babel/plugin-transform-runtime",
{
...
}
]
]
}
輸出:
我們會發現,Promise
跟includes
都沒有被墊平,因為chrome 80
已經支援了
總結
@babel/preset-env
是以全域性方式墊平,@babel/plugin-transform-runtime
是以區域性變數方式墊平,兩者我們應該選擇其一,不要又用@babel/preset-env
配置方式,又用@babel/plugin-transform-runtime
配置方式,這樣肯定會出現一些奇奇怪怪的問題。- 因為使用
@babel/plugin-transform-runtime
墊平是以區域性變數的方式來墊平,所以@babel/plugin-transform-runtime
這種配置方式更適合來做 庫 的開發。它可以很好的幫我們的庫與使用者的專案解耦。
參考文章:babel-plugin-transform-runtime
其他
案例 preset-env-useBuiltIns-config 裡面有個
stage-1
階段的提案API
—— Array.prototype.lastItem(取陣列最後一項)。本來是想用Array.prototype.uniqueBy
這個當前處在stage-1
的API
來給大家做例子的,結果發現編譯以後在IE 11
有問題。所以給Babel
提了個 issues :目前應該是修復了,在等合併。復現問題的程式碼包在 babel-use-proposals-problem,感興趣的朋友也可以
Fork
自己瞅瞅。說這個事主要也是想表達,學習還是不能停止(不是卷啊,還是要有學習的習慣)。在講
@babel/plugin-transform-runtime
如何配置時,我們說到開啟{version: 3, proposals: true}
時,可以以區域性變數的方式對提案階段的ES6+
API
墊平。但是經過測試發現,有些提案階段的
API
,用這個方法似乎是不能按預期實現的,所以又提了個 issues ,有個Babel
之一的大佬說可以用babel-plugin-polyfill-corejs3
來實現:關於
babel-plugin-polyfill-corejs3
這塊,其實Babel
還有一種墊平配置方式,是使用 babel-polyfills 這個包來實現的,這塊後期再看看要不要出文章聊聊。
最後
透過以上的瞭解,我們最後來總結一下這個配置。
如果我們開發的專案是應用程式,或者大型的專案,那我們可以這麼配置:
// Babel配置 const presets = [ [ '@babel/preset-env', { modules: false, // 或者只想用墊平我們程式碼中用到的 --> useBuiltIns: 'usage', useBuiltIns: 'entry', corejs: { version: '3.27.2', proposals: true } } ] ]; const plugins = [ '@babel/plugin-transform-runtime' ]; module.exports = {plugins, presets}; // package.json { ..., // 設定目標環境 "browserslist": [ "ie 11" ] } // 入口檔案 // ---- useBuiltIns: 'entry'時,需要引入以下---- // 墊平全部ES6+穩定版API import 'core-js/stable'; // ---- 或者 ----- // 墊平所有ES6+ API,包括提案階段 import 'core-js';
---
如果我們是想開發一個第三方庫,我們可以這麼配置:
// Babel配置 const presets = [ [ '@babel/preset-env', { modules: false } ] ]; const plugins = [ [ '@babel/plugin-transform-runtime', { corejs: { version: 3, proposals: true } } ] ]; module.exports = {plugins, presets}; // package.json { ..., // 設定目標環境 "browserslist": [ "ie 11" ] } // 入口檔案 const Method = { wait(delay) { return new Promise(resolve => setTimeout(() => resolve(), delay); } } ...
文章涉及到的例子,已經上傳 Github,覺得有幫助的話,歡迎Star
或者Fork
學習。
如果讀完這篇文章的你,覺得真的有幫助到,歡迎點贊收藏;如果有異同點,歡迎在評論區討論。
本文參與了SegmentFault 思否寫作挑戰賽,歡迎正在閱讀的你也加入。