Babel配置不要再“複製貼上”了,帶你自己配一個Babel

limingcan發表於2023-02-13

前言

問題

我們在使用各種打包工具,需要配置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大體由兩個功能組成:

    1. 編譯ES6+最新語法(letclass() => {}等)
    2. 實現舊版本瀏覽器不支援的ES6+APIPromiseSymbolArray.prototype.includes等)
  • @babel/preset-env有以下兩個功能:

    1. 只編譯ES6+語法
    2. 它並不提供polyfill,但是可以透過配置我們程式碼執行的目標環境,從而控制polyfill的匯入跟語法編譯,使ES6+的新特性可以在我們想要的目標環境中順利執行
  • @babel/plugin-transform-runtime也有以下兩個功能:

    1. @babel/runtime@babel/plugin-transform-runtime兩者配合,可以減少打包體積
    2. 也有一個配置功能,用來處理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的時候,需要設定這個配置項

配置

它有兩種配置方式:

  1. 直接設定core-js版本號

    ...
    {
        useBuiltIns: 'usage',
        corejs: '3.27.2'
    }
    ...
  2. 配置corejs

    ...
    {
        useBuiltIns: 'usage',
        corejs: {
            version: '3.27.2',
            // 是否編譯提案階段ES6+ API
            proposals: false
        },
    }
    ...

注意

  1. 當我們的useBuiltIns不為false的時候,需要設定corejs這個配置項
  2. 2版本的core-js已經不建議使用了;我們用當然要用最新的,目前最新的版本是core-js@3.27.2
  3. 我們安裝的core-js要儘量保持最新,因為越新的包,包含的polyfill才會越多
  4. 我們設定corejs的版本號時,不要直接指定2或者3,它會被解析為2.0或者3.0。所以,我們應該帶上子版本號3.27.2),這樣才會有最新的polyfill
  5. 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.anyPromise.allPromise.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方法。

總結

所以我們可以總結出,它的執行原理大致是這樣的:

  1. 我們需要手動import所有或者某塊polyfill
  2. Babel會根據我們設定的targets(目標環境),來判斷我們手動import所有或者某塊polyfill是不是當前缺失的
  3. 如果是的話,就會把我們手動import所有或者某塊polyfill,拆分成很多小模組,引入我們目標環境不支援的模組
注意
  • 為了避免一些奇奇怪怪的問題,我們手動importpolyfill應該統一在入口檔案(我們現在的工程專案一般都會有一個入口檔案)
  • 如果我們想一勞永逸,直接把當前環境所有不支援的ES6+ API墊平,那我們就import 'core-js/stable'(這會墊平當前targets不支援的所有穩定版本的ES6+ API,所以也會導致包變大)
  • 如果我們只想單純墊平某個ES6+ API(前提是targets不支援這個API,否則手動import了也沒用;例如只想墊平Promise),那我們import 'core-js/es/promise就可以了
  • 如果想墊平提案階段的API,則也需要手動import對應提案的polyfillimport "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不支援它,並且我們程式碼中用到了它

總結

所以我們可以總結出,它的執行原理大致是這樣的:

  1. 我們不需要手動import所有或者某塊polyfill
  2. Babel會根據我們當前程式碼中用到的ES6+ API,並判斷當前的targets支不支援我們用到的這個ES6+ API
  3. 如果不支援的話,則自動匯入這個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'

  1. 我們墊平的polyfill,都是注入到window全域性的,或者是某個內建物件的原型(prototype)上,這影響到了全域性
  2. 一勞永逸的方式會墊平當前targets所有不支援的ES6+ API,這雖然方便,但這會導致包變得很大

如果配置是useBuiltIns: 'usage'

  1. 它也會將墊平的polyfill注入到全域性。
  2. 由於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-utilsoptimizeImage方法,生成一個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.0regenerator-runtime包裡的內容,會以區域性變數的方式內聯注入到我們的程式碼中,這樣我們就不需要全域性提供一個regeneratorRuntime物件。

例如我們使用了class語法糖跟async function() {},然後用@babel/runtime@babel/plugin-transform-runtime(預設情況下,helpersregenerator值為true)配合使用,編譯後如下圖:
pic_17.png


當我們把helpersregenerator的值設為false
pic_18.png

我們會發現我們的輔助函式,跟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-corejs21. 只能編譯支援全域性變數(如Promise)和靜態屬性(如Array.from);<br/>2. 不能編譯例項相關方法([].includes
3@babel/runtime-corejs31. 既能編譯能編譯支援全域性變數和靜態屬性,又能編譯例項方法
2. 開啟proposals: true,還可以編譯提案階段的API

我們用這個例子 transform-runtime-config 體驗一下。

  • 如果配置的是corejs: 2的話,會怎麼樣:

    我們會發現,例項方法includes沒被墊平,提案APIMath.signbit)也沒有被墊平;Promise是以區域性變數的方式出現在我們的程式碼中。

  • 我們再看看配置的是corejs: {version: 3, proposals: true}

我們會發現,例項方法includes被墊平,提案APIMath.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",
            {
                ...
            }
        ]
    ]
}

輸出:

我們會發現,Promiseincludes都沒有被墊平,因為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-1API來給大家做例子的,結果發現編譯以後在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 思否寫作挑戰賽,歡迎正在閱讀的你也加入。

相關文章