Babel做爲一個JavaScript的語法編譯器,能夠將ES6/7/8
代碼轉爲ES5
代碼,從而在現有環境執行。html
可是初次配置.babelrc
的時候,各類presets
、plugins
看的眼花繚亂,不知道如何下手,下面就本身學習Babel時遇到的問題作一下總結:node
若是你是初次接觸babel,推薦閱讀阮一峯的《 Babel 入門教程》
按照Babel官網的介紹,其實Preset和Stage-X都是歸屬到Plugin裏面的,只不過所覆蓋的範圍不一樣而已。webpack
舉個例子,若是須要轉換ES2015(ES6)的語法,那麼你能夠在.babelrc
的plugins
中按需引入check-es2015-constants
、es2015-arrow-functions
、es2015-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中,這樣你只須要在.babelrc
的presets
加入es2015
一個配置就能夠完成所有ES2015語法的支持了:git
// .babelrc { "presets": [ "es2015" ] }
另外,不管是Plugin仍是Preset,有很多都有單獨屬於本身的配置項,具體如何操做的能夠看一下官網的說明。github
上面介紹了Plugin與Preset,那麼Stage-X就很好理解了,stage-0
、stage-1
、stage-2
、stage-3
、分別對應的就是進入標準以前的5個階段,不一樣stage-4
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
{ [string]: number | string }
,默認 {}
;須要支持的環境,可選例如:chrome
, edge
, firefox
, safari
, ie
, ios
, node
,甚至能夠指定版本,如node: "6.10"
或者node: "current"
表明使用當前的版本;segmentfault
number | string | "current" | true
;指定node
的版本,例如:6.10
;api
Array<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在運行的時候是怎麼處理的呢?總結一下,規律大概有如下幾點:
["es2015", "stage-0"]
,具體細節能夠看這個。摘自《 如何寫好.babelrc?Babel的presets和plugins配置解析》
babel-polyfill
與babel-runtime
的選擇Babel默認只轉換新的JavaScript語法,而不轉換新的API,好比Iterator
、Generator
、Set
、Maps
、Promise
等等全局對象,以及一些定義在全局對象上的方法(好比Object.assign
)都不會轉碼,具體的能夠參考babel-plugin-transform-runtime
模塊的definitions.js文件。
babel-polyfill
與babel-runtime
就是爲了解決這種全局對象或者全局對象方法不足的問題,而誕生的2種解決方式。
固然,你還能夠用promise-polyfill
此類Polyfill解決全局對象的問題;
或者用lodash
此類Utils解決Object.assign
這種方法擴展的問題。
先說說babel-polyfill
,它的作法比較暴力,就是將全局對象統統污染一遍,這樣作的壞處有幾點:
可是,這樣作也有好處,若是你的運行環境比較low,好比說Android一些老機子,而你有須要大量使用Promise
、Object.assign
、Array.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 補充
關於babel
與webpack
結合使用的教程網上已經有不少了,有很多卻還在用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
的模塊語法轉換爲AMD
、CommonJS
、UMD
之類的模塊化標準語法,可是如今webpack已經把這個事情作了,因此就不須要babel
來作了,可是babel
配置項中的modules
默認值是commonjs
,因此你須要將modules
設置爲false
才行,否則就衝突了。
本文先發佈於個人我的博客《 Babel筆記》,後續若有更新,能夠查看原文。