關於Babel配置項的這點事

  • 2019 年 12 月 30 日
  • 筆記

摘要: IE雖然沒落了,Babel還是要用的…

Fundebug經授權轉載,版權歸原作者所有。

Babel作為一個JavaScript的語法編譯器,可以將ES6/7/8程式碼轉為ES5程式碼,從而在現有環境執行。

但是初次配置.babelrc的時候,各種presetsplugins看的眼花繚亂,不知道如何下手,下面就自己學習Babel時遇到的問題做一下總結:

如果你是初次接觸babel,推薦閱讀阮一峰的《Babel 入門教程

Plugin、Preset、Stage-X的關係

按照Babel官網的介紹,其實PresetStage-X都是歸屬到Plugin裡面的,只不過所覆蓋的範圍不同而已。

舉個例子,如果需要轉換ES2015(ES6)的語法,那麼你可以在.babelrcplugins中按需引入check-es2015-constantses2015-arrow-functionses2015-block-scoped-functions等等幾十個不同作用的plugin:

// .babelrc  {    "plugins": [      "check-es2015-constants",      "es2015-arrow-functions",      "es2015-block-scoped-functions",      // ...    ]  }

但是Babel團隊為了方便,將同屬ES2015的幾十個Transform Plugins集合到babel-preset-es2015一個Preset中,這樣你只需要在.babelrcpresets加入es2015一個配置就可以完成全部ES2015語法的支援了:

// .babelrc  {    "presets": [      "es2015"    ]  }

另外,不論是Plugin還是Preset,有不少都有單獨屬於自己的配置項,具體如何操作的可以看一下官網的說明

上面介紹了Plugin與Preset,那麼Stage-X就很好理解了,stage-0stage-1stage-2stage-3stage-4分別對應的就是進入標準之前的5個階段,不同stage-x之間存在依賴關係,數字越小,階段越靠後,靠後階段包含前面階段所有的功能,簡單理解就是stage-0包含stage-1/2/3的內容,所以如果你不知道需要哪個stage-x的話,直接引入stage-0就好了。

PS: babel-preset-stage-4已經整合入Presets不單獨發布了。

以上就是一些基礎概念,目前,官方推薦使用babel-preset-env,它可以根據你的配置結合compat-table來幫你自動引入你需要的plugins,它有很多配置項,下面介紹幾個常用的:

  • targets{ [string]: number | string },默認 {}

需要支援的環境,可選例如:chrome, edge, firefox, safari, ie, ios, node,甚至可以指定版本,如node: "6.10"或者node: "current"代表使用當前的版本;

  • targets.nodenumber | string | "current" | true

指定node的版本,例如:6.10

  • targets.browsersArray<string> | string

指定需要兼容的瀏覽器清單,具體參考browserslist,例如:["last 2 versions", "safari >= 7"]

例如需要配置兼容["last 2 versions", "safari >= 7"]babel-preset-env

// .babelrc  {    "presets": [      ["env", {        "targets": {          "browsers": ["last 2 versions", "safari >= 7"]        }      }]    ]  }

此外,不同的plugins和presets或許有些功能是重複的,有些存在依賴關係,在配置的時候還有前後順序的不同,那麼Babel在運行的時候是怎麼處理的呢?總結一下,規律大概有以下幾點:

  1. plugins優先於presets進行編譯;
  2. plugins按照數組的index增序(從數組第一個到最後一個)進行編譯;
  3. presets按照數組的index倒序(從數組最後一個到第一個)進行編譯,因為作者認為大部分會把presets寫成["es2015", "stage-0"],具體細節可以看這個

摘自《如何寫好.babelrc?Babel的presets和plugins配置解析

babel-polyfill與babel-runtime的選擇

Babel默認只轉換新的JavaScript語法,而不轉換新的API,比如IteratorGeneratorSetMapsPromise等等全局對象,以及一些定義在全局對象上的方法(比如Object.assign)都不會轉碼,具體的可以參考babel-plugin-transform-runtime模組的definitions.js文件。

babel-polyfillbabel-runtime就是為了解決這種全局對象或者全局對象方法不足的問題,而誕生的2種解決方式。

當然,你還可以用promise-polyfill此類Polyfill解決全局對象的問題; 或者用lodash此類Utils解決Object.assign這種方法擴展的問題。

先說說babel-polyfill,它的做法比較暴力,就是將全局對象通通污染一遍,這樣做的壞處有幾點:

  1. 可能會增加很多根本沒有用到的polyfill;
  2. 可能會污染子模組的局部作用域,嚴重的或許會導致衝突;

但是,這樣做也有好處,如果你的運行環境比較low,比如說Android一些老機子,而你有需要大量使用PromiseObject.assignArray.find之類的全局對象或者其所屬方法,那麼使用babel-polyfill,絕對是一勞永逸。

接著,再來說說babel-runtime,相對而言,它的處理方式比較溫柔,套用步步高的廣告詞就是哪裡需要加哪裡,比如說你需要Promise,你只需要import Promise from 'babel-runtime/core-js/promise'即可,這樣不僅避免污染全局對象,而且可以減少不必要的程式碼。

不過,如果N個文件都需要Promise,難道得一個個文件的加import Promise from 'babel-runtime/core-js/promise'么,顯然不是,Babel已經為這樣情況考慮過了,只需要使用babel-plugin-transform-runtime就可以輕鬆的幫你省去手動import的痛苦,而且,它還做了公用方法的抽離,哪怕你有100個模組使用了Promise,但是promise的polyfill僅僅存在1份,所有要的地方都是引用一地方,具體的配置參考如下:

// .babelrc  {    "presets": [      "env",      "stage-0"    ],    "plugins": [      "transform-runtime"    ],    "comments": false  }

寫在最後,我在Github上開了一個項目,做了幾個測試,有興趣的可以一起來試試看。

babel與webpack

關於babelwebpack結合使用的教程網上已經有很多了,有不少卻還在用v1.*的版本(不推薦),從而在過渡到v2.*或者v3.*(推薦)的版本時,碰到一個關於babel的配置問題,示例如下:

// .babelrc - webpack v1.*  {    "presets": [      "env",      "stage-0"    ]  }    // .babelrc - webpack v2.* - v3.*  {    "presets": [      ["env", {          "modules": false      }],      "stage-0"    ]  }

很明顯,一眼就能看出相對於v1.*的版本,v2.*或者v3.*版本多了"modules": false這項配置,如果仔細看官網的遷移指南,你就能明白了,以前你可能需要用babel來將ES6的模組語法轉換為AMDCommonJSUMD之類的模組化標準語法,但是現在webpack已經把這個事情做了,所以就不需要babel來做了,但是babel配置項中的modules默認值commonjs,所以你需要將modules設置為false才行,不然就衝突了。

參考資料

本文先發佈於我的個人部落格《Babel筆記》,後續如有更新,可以查看原文。

版權聲明

轉載時請註明作者 Fundebug以及本文地址: https://blog.fundebug.com/2018/11/01/about-babel-configuration/

您的用戶遇到BUG了嗎?

體驗Demo 免費使用

.copyright *{box-sizing:border-box}