Babel是一個JavaScript編譯器
Babel 是一個工具鏈,主要用於將 ECMAScript 2015+ 版本的程式碼轉換為向後相容的 JavaScript 語法,以便能夠執行在當前和舊版本的瀏覽器或其他環境中。下面列出的是 Babel 能為你做的事情:
- 語法轉換
- 通過 Polyfill 方式在目標環境中新增缺失的特性 (通過 @babel/polyfill 模組)
- 原始碼轉換 (codemods)
Presets(預設)
一、@babel/preset-env (官方preset)
作用:預設目標環境,新增我們需要的預設環境
babel-preset-env將基於你的實際瀏覽器及執行環境,自動的確定babel外掛及polyfill,編譯ES2015及此版本以上的語言,在沒有配置項的情況下,babel-preset-env表現的同babel-preset-latest一樣(或者可以說同babel-preset-es2015, babel-preset-es2016, and babel-preset-es2017結合到一起,表現的一致)。
1 { 2 "presets": ["@babel/preset-env"] 3 } 4 5 { 6 "presets": ["@babel/preset-env”,option] 7 }
常用配置欄位:
1、targets: String | Array | { [String]: string } 。預設為{}
這一屬性說明了當前的專案的適用環境。可以編寫字串的內容,作為boswerlist的遍歷條件。例如:"targets": "> 0.25%, not dead" 或者也可以使一個物件。來設定對於每一個瀏覽器最低版本的控制。例如:{ "targets": { "chrome": "58", "ie": "11" } },其中的瀏覽器關鍵字從如下之中選取:chrome, opera, edge, firefox, safari, ie, ios, android, node, electron
2、 boswerlist:
是在不同的前端工具之間共用目標瀏覽器和 node 版本的配置工具,browserslist可以在babel之中配置,來告訴babel具體轉化程式碼的規則。有三種配置方式:
- 在.babelrc或者babel.config.js中去配置
1 { 2 "presets": [ 3 [ 4 "@babel/preset-env", 5 { 6 "targets": { 7 "node": "4", 8 "chrome": "58", 9 "ie": "11" 10 } 11 } 12 ] 13 ] 14 }
- 在package.json 裡面增加如下配置
1 { 2 "browserslist": [ 3 "last 1 version", "> 1%", 4 "maintained node versions", "not dead" 5 ] 6 }
- 在工程的根目錄下存在.browerslistrc配置檔案
# 註釋是這樣寫的,以#號開頭 last 1 version > 1% maintained node versions not dead
配置檔案來源:browerslist 將使用如下配置檔案限定的的瀏覽器和 node 版本範圍:
- 工具 options,例如 Autoprefixer 工具配置中的 browsers 屬性。
- BROWERSLIST 環境變數。
- 當前目錄或者上級目錄的browserslist配置檔案。
- 當前目錄或者上級目錄的browserslistrc配置檔案。
- 當前目錄或者上級目錄的package.json配置檔案裡面的browserslist配置項(推薦)。
- 如果上述的配置檔案缺失或者其他因素導致未能生成有效的配置,browserslist 將使用預設配置> 0.5%, last 2 versions, Firefox ESR, not dead。
實踐經驗:
- 僅僅當你在特定瀏覽器上開發類似於資訊亭之類的 web app 的時候,才可以用類似last 2 Chrome versions的查詢條件來鎖定特別具體的瀏覽器品牌和版本。市面上有各種各樣的瀏覽器,同時瀏覽器的版本碎片化也很嚴重,如果你在開發一款通用的 webapp,那就應該考慮瀏覽器多樣性導致的相容問題。
- 如果你不想用 browserslsit 的預設設定,推薦使用last 1 version, not dead 和 > 0.2%(或者> 1% in US,> 1% in my stats).僅僅使用last n versions 將新增太多的廢棄瀏覽器到工程裡面來,同時也並沒有有效的覆蓋那些佔有率仍然很高的老版本瀏覽器。
- 不移除某些瀏覽器,是因為你不瞭解它們的分佈。Opera mini 在非洲有一億使用者,全球範圍內,它也比 微軟的 Edge 瀏覽器更加流行。QQ 瀏覽器的使用量比桌面端的火狐和 Safari 瀏覽器加起來還多。
查詢條件列表:可以用如下查詢條件來限定瀏覽器和 node 的版本範圍(大小寫不敏感):
- > 5%: 基於全球使用率統計而選擇的瀏覽器版本範圍。>=,<,<=同樣適用。
- > 5% in US : 同上,只是使用地區變為美國。支援兩個字母的國家碼來指定地區。
- > 5% in alt-AS : 同上,只是使用地區變為亞洲所有國家。這裡列舉了所有的地區碼。
- > 5% in my stats : 使用定製的瀏覽器統計資料。
- cover 99.5% : 使用率總和為99.5%的瀏覽器版本,前提是瀏覽器提供了使用覆蓋率。
- cover 99.5% in US : 同上,只是限制了地域,支援兩個字母的國家碼。
- cover 99.5% in my stats :使用定製的瀏覽器統計資料。
- maintained node versions :所有還被 node 基金會維護的 node 版本。
- node 10 and node 10.4 : 最新的 node 10.x.x 或者10.4.x 版本。
- current node :當前被 browserslist 使用的 node 版本。
- extends browserslist-config-mycompany :來自browserslist-config-mycompany包的查詢設定
- ie 6-8 : 選擇一個瀏覽器的版本範圍。
- Firefox > 20 : 版本高於20的所有火狐瀏覽器版本。>=,<,<=同樣適用。
- ios 7 :ios 7自帶的瀏覽器。
- Firefox ESR :最新的火狐 ESR(長期支援版) 版本的瀏覽器。
- unreleased versions or unreleased Chrome versions : alpha 和 beta 版本。
- last 2 major versions or last 2 ios major versions :最近的兩個發行版,包括所有的次版本號和補丁版本號變更的瀏覽器版本。
- since 2015 or last 2 years :自某個時間以來更新的版本(也可以寫的更具體since 2015-03或者since 2015-03-10)
- dead :通過last 2 versions篩選的瀏覽器版本中,全球使用率低於0.5%並且官方宣告不在維護或者事實上已經兩年沒有再更新的版本。目前符合條件的有 IE10,IE_Mob 10,BlackBerry 10,BlackBerry 7,OperaMobile 12.1。
- last 2 versions :每個瀏覽器最近的兩個版本。
- last 2 Chrome versions :chrome 瀏覽器最近的兩個版本。
- defaults :預設配置> 0.5%, last 2 versions, Firefox ESR, not dead。
- not ie <= 8 : 瀏覽器範圍的取反。
- 可以新增not在任和查詢條件前面,表示取反
注意事項:
Browserslist 會處理瀏覽器的每個版本,所以應該避免配置這樣的查詢條件Firefox > 0.多個查詢條件組和
在一起之後,其之間的的覆蓋是以OR 的方式,而是不是AND,也就是說只要瀏覽器版本符合篩選條件裡面的
一種即可。
所有的查詢條件均基於Can I Use的支援列表。例如:last 3 ios versions 可能會返回8.4, 9.2, 9.3(混合了
主版本和次版本),然而last 3 Chrome versions可能返回50, 49, 48(只有主版本),總之一切以 CanIUse網
站收集的瀏覽器版本資料為準。
不同環境的差異化配置:
"browserslist": { "production": [ "> 1%", "ie 10" ], "development": [ "last 1 chrome version", "last 1 firefox version" ] }
3、useBuiltIns : "usage"| "entry"| false,預設為false。
此選項配置@babel/preset-env如何處理polyfill。usage和entry選項配置上都是增加按需引入的功能。
- “useBuiltIns”: “usage"
在檔案需要的位置單獨按需引入,可以保證在每個bundler中只引入一份。當前模式類似於@babel/plugin-transform-runtime,polyfill區域性使用,製造一個沙盒環境,不造成全域性汙染
- “useBuiltIns”: “entry”
在專案入口引入一次(多次引入會報錯),外掛@babel/preset-env會將把@babel/polyfill根據實際需求打散,只留下必須的,例如:
In
import "@babel/polyfill”;
Out (實際引入取決於環境不同)
import "core-js/modules/es6.promise";
import "core-js/modules/es7.string.pad-start";
import "core-js/modules/es7.string.pad-end";
import "core-js/modules/es7.array.includes";
4、modules
選項用於模組轉化規則設定,可選配置包括:"amd" | "umd" | "systemjs" | "commonjs" | false, 預設使用 "commonjs"。即,將程式碼中的ES6的import轉為require。
如果你當前的webpack構建環境是2.x/3.x,推薦將modules設定為false,即交由 Webpack 來處理模組化,通過其 TreeShaking 特性將有效減少打包出來的 JS 檔案大小。這部分參考這裡的回答:ECMAScript 6 的模組相比 CommonJS 的require (...)有什麼優點?
5、include :Array<string|RegExp>,預設為[]
轉譯時必須包含的外掛
6、exclude: Array<string|RegExp>,預設為[]
轉譯時排除在外的外掛
二、@babel/preset-react(官方preset)
作用:react 語法轉譯
1、預設包含的外掛
此 preset 始終包含以下外掛:
- @babel/plugin-syntax-jsx
- @babel/plugin-transform-react-jsx
- @babel/plugin-transform-react-display-name
以及以下開發環境下的選擇輔助開發外掛:
PS:一般使用該預設都是預設值,不需要單獨配置外掛
配置引數:
- pragma
string 型別,預設值為 React.createElement。編譯 JSX 表示式時替用於換所使用的函式(function)。
- pragmaFrag
string 型別,預設值為 React.Fragment。編譯 JSX 片段時用於替換所用的元件。
- useBuiltIns
boolean 型別,預設值為 false。當外掛需要某項功能時,此引數用於確定是使用內建功能還是通過 polyfill 來模擬。
- development
boolean 型別,預設值為 false。用於確定是否開啟用於輔助開發的外掛,例如 @babel/plugin-transform-react-jsx-self 和 @babel/plugin-transform-react-jsx-source。當與 env 引數 配置或 js 配置檔案 一同使用時會非常有用。
- throwIfNamespace
boolean 型別,預設值為 true。如果使用了 XML 名稱空間標籤,此引數用於設定是否丟擲錯誤。例如:<f:image />。雖然 JSX 規範允許這樣做,但是預設情況下是被禁止的,因為 React 的 JSX 目前並不支援這 種方式。
三、@babel/preset-stage-x
作用:可以將處於某一階段的js語法編譯為正式版本的js程式碼
1、stage-X: 指處於某一階段的js語言提案。
提案共分為5個階段:
- stage-0:稻草人-只是一個大膽的想法
- stage-1:提案-初步嘗試
- stage-2:初稿-完成初步規範
- stage-3:候選-完成規範和瀏覽器初步實現
- stage-4:完成-將被新增到下一年釋出
如果不知道需要哪個stage-x的話,直接引入stage-0,stage-0包含所有stage-1所有外掛,stage-1包含所有stage-2所有外掛,stage-2包含所有stage-3所有外掛(每個stage包含的外掛就不列了,感興趣可以自行百度,可以參考看下http://www.bubuko.com/infodetail-1895965.html)
PS: babel-preset-stage-4已經整合入Presets不單獨釋出了
plugins(外掛)
Babel 是一個編譯器(輸入原始碼 => 輸出編譯後的程式碼)。就像其他編譯器一樣,編譯過程分為三個階段:解析、轉換和列印輸出。
現在,Babel 雖然開箱即用,但是什麼動作都不做。它基本上類似於 const babel = code => code; ,將程式碼解析之後再輸出同樣的程式碼。如果想要 Babel 做一些實際的工作,就需要為其新增外掛。
除了一個一個的新增外掛,你還可以以 preset 的形式啟用一組外掛。
一、轉換外掛
作用:這些外掛用於轉換你的程式碼。(轉換外掛將啟用相應的語法外掛,因此你不必同時指定這兩種外掛。)
1、ES3
2、ES5
3、ES2015(ES6)
- arrow-functions
- block-scoped-functions
- block-scoping
- classes
- computed-properties
- destructuring
- duplicate-keys
- for-of
- function-name
- instanceof
- literals
- new-target
- object-super
- parameters
- shorthand-properties
- spread
- sticky-regex
- template-literals
- typeof-symbol
- unicode-regex
4、ES2016
5、ES2017
6、ES2018
- async-generator-functions
- dotall-regex
- named-capturing-groups-regex
- object-rest-spread
- optional-catch-binding
- unicode-property-regex
7、Modules
8、Experimental
- class-properties
- decorators
- do-expressions
- export-default-from
- export-namespace-from
- function-bind
- function-sent
- logical-assignment-operators
- nullish-coalescing-operator
- numeric-separator
- optional-chaining
- partial-application
- pipeline-operator
- private-methods
- throw-expressions
9、Minification
- inline-consecutive-adds
- inline-environment-variables
- member-expression-literals
- merge-sibling-variables
- minify-booleans
- minify-builtins
- minify-constant-folding
- minify-dead-code-elimination
- minify-flip-comparisons
- minify-guarded-expressions
- minify-infinity
- minify-mangle-names
- minify-numeric-literals
- minify-replace
- minify-simplify
- minify-type-constructors
- node-env-inline
- property-literals
- regexp-constructors
- remove-console
- remove-debugger
- remove-undefined
- simplify-comparison-operators
- undefined-to-void
10、React
- react-constant-elements
- react-display-name
- react-inline-elements
- react-jsx
- react-jsx-compat
- react-jsx-self
- react-jsx-source
11、其他
- external-helpers
- flow-strip-types
- jscript
- object-assign
- object-set-prototype-of-to-assign
- proto-to-assign
- regenerator
- runtime
- strict-mode
- typescript
二、語法外掛
這些外掛只允許 Babel 解析(parse) 特定型別的語法(而不是轉換)。(注意:轉換外掛會自動啟用語法外掛。因此,如果你已經使用了相應的轉換外掛,則不需要指定語法外掛。)
{ "parserOpts": { "plugins": [ "jsx", "flow" ] } }
三、外掛/Preset路徑
如果外掛再 npm 上,你可以輸入外掛的名稱,babel 會自動檢查它是否已經被安裝到 node_modules 目錄下
{ "plugins": ["babel-plugin-myPlugin"] }
你還可以指定外掛的相對/絕對路徑。
{ "plugins": ["./node_modules/asdf/plugin"] }
四、外掛的短名稱
如果外掛名稱的字首為 babel-plugin-,你還可以使用它的短名稱:
1 { "plugins": [ 2 "myPlugin”, 3 "babel-plugin-myPlugin" // 兩個外掛實際是同一個 4 ] 5 }
這也適用於帶有冠名(scope)的外掛:
1 { "plugins": [ 2 "@org/babel-plugin-name”, 3 "@org/name" // 兩個外掛實際是同一個 4 ] 5 }
五、外掛順序
- Plugin 會執行在 Preset 之前。
- Plugin 會從第一個開始順序執行。ordering is first to last.
- Preset 的順序則剛好相反(從最後一個逆序執行)。
常用外掛說明
1、babel-core //必備的核心庫
2、babel-loader //webpack loader配置必備
3、babel-preset-env //有了它,你不再需要新增2015、2016、2017,全都支援
4、babel-preset-stage-0 //有了它,你不再需要新增stage-1,stage-2,stage-3,預設向後支援
5、babel-plugin-transform-runtime 、babel-runtime //支援helpers,polyfill,regenerator配置
babel-plugin-transform-runtime該外掛主要做了三件事
- 自動轉換generators/async
- 使用core-js來按需給內建型別打上polyfill。(這一點和useBuiltIns:'usage'一樣)
- 通過helpers 選項自動移除嵌入的babel helper,並且用module引用來代替。否則每個檔案中都會加入這些inline babel helper,造成程式碼冗餘。預設為ture。
@babel/runtime 和 @babel/polyfill 雖然都是為內建型別打上墊片,但是@babel/runtime是在模組內起作用,不會汙染全域性的Promise,Map...。所以例項的方法不會被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份,所有要的地方都是引用一地方,具體的配置參考如下:
1 // .babelrc 2 { 3 "presets": [ 4 "env", 5 "stage-0" 6 ], 7 "plugins": [ 8 "transform-runtime" 9 ], 10 "comments": false 11 }
@babel/plugin-transform-runtime 還可以和preset-env中的useBuiltIns一起使用,作用的順序按照plugins --> presets 的順序,也就是先使用@babel/plugin-transform-runtime 打上墊片,然後再使用@babel/polyfill 再打上一次墊片。
如果使用react:
1、babel-plugin-transform-decorators-legacy //支援修飾符語法 @connect
2、babel-preset-react //支援解析react語法,如果使用vue把react替換成vue就好
如果需要熱更新:
1、react-hot-loader //雖然它長得不像babel,但是它也需要在babelrc做配置
最後總結
主要幾個配置
- presets : 預設,外掛的集合,倒序執行
- plugins : 外掛,先執行外掛,在執行預設,順序執行
- ignore : 忽略的檔案
- minify : 壓縮程式碼
- common : 是否需要註釋
- env : 設定不同的環境,應用不同的配置,配置取值:BABEL_ENV,如若沒有取 NODE_ENV 的值,預設為 development.
常見預設
- env : 用於替換 es2015 / es2016 / es2017 的預設。根據環境引入外掛
- react :react的外掛集合
- react-optimize : react 程式碼優化,如去除 propsType 減少生產上面程式碼
- stage-x :草案程式碼外掛集合
- flow : flow 外掛集合
- minify : 程式碼優化的集合
- typescript : typescript 外掛集合
常用外掛
- transform-async-to-generator : 非同步函式 async/await 外掛
- transform-decorators-leagacy : 裝飾器外掛
- syntax-dynamic-import :import() 外掛
- transform-runtime : 輔助器外掛,用於ployfill
- transform-object-rest-spread : 用於合併 var test = {a:1,b2};var t = {...test,n:1}
- transform-funciton-bind : 用於編譯 obj::fun => fun.bind(obj)
資料來源: