在一些新框架的代碼中,常基於es6/7標準來書寫代碼。鑑於這些標準被沒有被瀏覽器廣泛支持,我們一般使用babel來將使用e6/7標準書寫的代碼降級編譯(或者説轉譯)為瀏覽器可解析的es3/5代碼。
以.babelrc文件配置babel為例,presets預設編譯規則(預設的編譯插件集合)可以設置stage-0 至 stage-3, stage-0包含了stage-1 至 stage-3,也就是説如果設置為stage-0,stage-1 至 stage-3的編譯功能默認都有了。
Stage 0:提案,經過 TC39 成員提出即可
Stage 1:初步嘗試
Stage 2:完成初步規範
Stage 3:完成規範以及主流瀏覽器初步實現
Stage 4:完全完成,將被添加到下一年度進行發佈,因此不會存在針對這個階段的配置項
Stage < 4的提案,不保證都能成為真正的標準並定稿。
stage-3包括以下插件:
transform-async-to-generator 支持async/await
transform-exponentiation-operator 支持冪運算符語法糖,用兩個**表示
stage-2包括stage-3的所有插件,額外還包括以下插件:
syntax-trailing-function-commas 支持尾逗號函數,額...很雞肋
transform-object-reset-spread 支持對象的解構賦值
stage-1包括stage-2所有插件,額外還包括以下插件:
transform-class-constructor-call 支持class的構造函數
transform-class-properties 支持class的static成員(靜態屬性與靜態方法)
transform-decorators 支持es7的裝飾者模式即@,這其實是很有用的特性,對於HOC來説這是一個不錯的語法糖
transform-export-extensions 支持export方法
stage-0包括stage-1所有插件,額外還包括以下插件:
transform-do-expressions 支持在jsx中書寫if/else
transform-function-bind 支持::操作符來切換上下文,並且支持鏈式調用,作用類似於es5的bind
每個插件所支持的特性在代碼上的具體體現可查看es6/7標準等詳細資料,或babel官方站點,
Babel默認只轉換新的JavaScript語法,但不會去轉換新的 API ,比如 Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局對象,以及一些定在全局對象上定義的方法,例如:Object.assign等,這些都不會被轉換。 默認不轉碼的 API 非常多,詳情查看。
也就是當我們使用ES2015語法進行開發的時候,要去適配一些在ES2015定稿之前發行的瀏覽器,可能還需要使用到babel-polyfill,來保證上述提到的不被轉換的API等都能夠有ES3/5的支持,從而確保我們的項目在運行的時候不會因語法報錯而白屏。
在實際配置babel presets stage的時候,可以根據業務要求、書寫愛好、文件大小以及要兼容的瀏覽器及其版本來酌情設置。
對於babel的核心和其他插件,在實際項目開發中我們常用的到的還有:
babel-core
它是babel實現最基礎代碼轉譯功能的核心,用於將我們書寫的高級EcmaScript語法轉成AST語法抽象樹,分發給不同的插件進行語法分析,進而轉譯成低級的EcmaScript語法。
babel-runtime
包含降級轉譯所需的各種helper方法,以實現ES6的新特性,比如各種內置對象、_extend、_defineProperty等,還包括對各種異步語法的轉換。
babel-plugin-transform-runtime
這個插件的存在解決了polyfill引入而帶來的全局變量污染和語法降級helper重複的問題。試想如果我們的項目不是全寫在一個JS文件裏,而是分散到不同的JS文件中去的,同一個高級EcamaScript語法可能在多個JS文件中被使用到,在降級轉譯高級語法的時候,會出現多個用於降級轉譯的helper,比如_extend、_defineProperty等,文件分散得越多,重複得可能性越大,最後轉譯出的靜態資源也就越大,這是很可怕的。這個插件的存在就是為了解決這個問題,他提供了從 babel-runtime 獲取helper並插入到每個需要編譯的JS文件內的功能。當每個JS文件被轉譯時,其所需的helper都從 babel-runtime
babel-plugin-import
這是一個由antd發佈的插件,支持模塊的按需加載。比如我們使用React和Antd作為MVVM的庫和UI組件庫。對於Antd提供的UI組件我們可能並非所有的組件都有用到,因為一次性引入整個Antd(包括js和css)對我們來説不是必要的,而我們又不願意import一個組件很長的文件路徑和對應的樣式路徑,對於我們來説直接 import {Button} from 'antd';
還有其他的插件也有很大機率使用到,這取決於你的開發和測試需求,這裏就不再過多講解,在babel官網中會有相應介紹,有興趣的同學可以自行查看。
另外的,在.babelrc文件中,我們一般需要配置plugins和presets,對於plugins和presets可以這麼理解:
plugins的每個內容項為單獨的一個插件,執行順序從上到下。
而presets裏的每個內容項表示為實現某個功能的某些插件的集合,可能一個presets的配置項包含有多個插件,執行順位為從下到上。
總的執行順序為先執行plugins,再執行presets的內容。