關於Babel配置項的這點事

Babel做爲一個JavaScript的語法編譯器,能夠將ES6/7/8代碼轉爲ES5代碼,從而在現有環境執行。html

可是初次配置.babelrc的時候,各類presetsplugins看的眼花繚亂,不知道如何下手,下面就本身學習Babel時遇到的問題作一下總結:node

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

Plugin、Preset、Stage-X的關係

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

舉個例子,若是須要轉換ES2015(ES6)的語法,那麼你能夠在.babelrcplugins中按需引入check-es2015-constantses2015-arrow-functionses2015-block-scoped-functions等等幾十個不一樣做用的plugin:ios

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

可是Babel團隊爲了方便,將同屬ES2015的幾十個Transform Plugins集合到babel-preset-es2015一個Preset中,這樣你只須要在.babelrcpresets加入es2015一個配置就能夠完成所有ES2015語法的支持了:git

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

另外,不管是Plugin仍是Preset,有很多都有單獨屬於本身的配置項,具體如何操做的能夠看一下官網的說明github

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

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

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

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

須要支持的環境,可選例如:chrome, edge, firefox, safari, ie, ios, node,甚至能夠指定版本,如node: "6.10"或者node: "current"表明使用當前的版本;segmentfault

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

指定node的版本,例如:6.10api

  • 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-polyfillbabel-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上開了一個項目,作了幾個測試,有興趣的能夠一塊兒來試試看。


2017.8.30 補充

關於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才行,否則就衝突了。


參考資料
  1. http://www.ruanyifeng.com/blo...
  2. https://excaliburhan.com/post...
  3. https://segmentfault.com/q/10...
  4. https://github.com/brunoyang/...
  5. https://github.com/lmk123/blo...
  6. http://www.cnblogs.com/flying...
本文先發佈於個人我的博客《 Babel筆記》,後續若有更新,能夠查看原文。
相關文章
相關標籤/搜索