我們?yōu)槭裁磿褂胋abel?因為我們會使用很多es的新語法。但瀏覽器的支持卻還不完善。所以我們只能使用babel編譯器來幫助我們。
如果我們還使用了webpack的話,我們會在webpack中增加babel-loader
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test')]
},
在babel5的時代,babel屬于全家桶型,只要安裝babel就會安裝babel相關的所有工具,
即裝即用。
但是到了babel6,具體有以下幾點變更:
移除babel全家桶安裝,拆分為單獨模塊,例如:babel-core、babel-cli、babel-node、babel-polyfill等;
使用babel的會自動識別.babelrc文件。
該文件用來設置轉碼規(guī)則和插件,基本格式如下。
{
"presets": [], // 設定轉碼規(guī)則
"plugins": [], //
}
plugin:,插件,通過配置不同的插件才能告訴babel,我們的代碼中有哪些是需要轉譯的。
preset:babel5會默認轉譯ES6和jsx語法,babel6轉譯的語法都要在perset中配置,preset簡單說就是一系列plugin包的使用。
為什么我們經(jīng)常會看到Stage 2這種插件?
ES即ECMAScrip。被納入到ES標準的語法必須要經(jīng)過如下五個階段:
Stage 0: strawman
Stage 1: proposal
Stage 2: draft - 必須包含2個實驗性的具體實現(xiàn),其中一個可以是用轉譯器實現(xiàn)的,例如Babel。
Stage 3: candidate - 至少要有2個符合規(guī)范的具體實現(xiàn)。
Stage 4: finished
除了已經(jīng)正式納入規(guī)范 (ES2015/6/7) 的特性,還有許多處于不同討論階段的特性提案 (stage 1/2/3/4)。這些討論中的特性嚴格來說還不算是標準,尤其是 stage 1/2 的特性,完全有可能被改動甚至是撤銷提案。因此從 babel 的角度來說,顯然不能夠默認啟用這些特性,而需要有可配置的選項讓用戶自行衡量風險,決定是否使用。
那么我們?nèi)绾闻袛辔覀冃枰褂玫膕tage是哪一個呢?
在TC39的提案中,有對應的一個詳細的列表表明哪種特性處于哪個階段:處于哪個階段
所以我們經(jīng)常會看到"stage-2"。
transform-runtime VS babel-polyfill
為什么需要 babel-polyfill?因為babel的轉譯只是語法層次的轉譯,例如箭頭函數(shù)、解構賦值、class,對一些新增api以及全局函數(shù)(例如:Promise)無法進行轉譯,這個時候就需要在代碼中引入babel-polyfill,讓代碼完美支持ES6+環(huán)境。但很多時候我們并不會使用所有ES6+語法,全局添加所有墊片肯定會讓我們的代碼量上升,之后會介紹其他添加墊片的方式。
那我們可以用到那個語法或者api增加哪個對應的插件呀。
{
"plugins": [
"transform-es2015-arrow-functions", //轉譯箭頭函數(shù)
"transform-es2015-classes", //轉譯class語法
"transform-es2015-spread", //轉譯數(shù)組解構
"transform-es2015-for-of" //轉譯for-of
]
}
這樣有個問題。這種通過transform添加的polyfill只會引入到當前模塊中,試想實際開發(fā)中存在多個模塊使用同一個api,每個模塊都引入相同的polyfill,大量重復的代碼出現(xiàn)在項目中,這肯定是一種災難。另外一個個的引入需要polyfill的transform挺麻煩的,而且不能保證手動引入的transform一定正確。所以我們使用transform-runtime
比較transform-runtime與babel-polyfill引入墊片的差異:
- 使用runtime是按需引入,需要用到哪些polyfill,runtime就自動幫你引入哪些,不需要再手動一個個的去配置plugins,只是引入的polyfill不是全局性的,有些局限性。而且runtime引入的polyfill不會改寫一些實例方法,比如Object和Array原型鏈上的方法,像前面提到的Array.protype.includes。
- babel-polyfill就能解決runtime的那些問題,它的墊片是全局的,而且全能,基本上ES6中要用到的polyfill在babel-polyfill中都有,它提供了一個完整的ES6+的環(huán)境。babel官方建議只要不在意babel-polyfill的體積,最好進行全局引入,因為這是最穩(wěn)妥的方式。
- 一般的建議是開發(fā)一些框架或者庫的時候使用不會污染全局作用域的babel-runtime,而開發(fā)web應用的時候可以全局引入babel-polyfill避免一些不必要的錯誤,而且大型web應用中全局引入babel-polyfill可能還會減少你打包后的文件體積(相比起各個模塊引入重復的polyfill來說)。
不過目前官方推薦babel-preset-env
這款preset能靈活決定加載哪些插件和polyfill。這樣,如果我們支持的瀏覽器較新,那么很多插件根本就不需要用到,既能保證瀏覽器兼容性,也能保證最佳的編譯速度和最小的 Polyfill 體積。
babel到底該如何配置
babel為什么要通過插件編譯
為什么vue-cli中babel的配置即使用babel-preset-env又使用transform-runtime
babel-preset-env是根據(jù)瀏覽器判斷需要加載的插件和polyfill而不是直接加載。transform-runtime和babel-polyfill都是引入polyfill。沒有polyfill的話env也沒的加載呀。
在babel-preset-env@2.x中已經(jīng)完全可以用useBuiltIns: usage來達到按需引入的目的,也就是說不再需要transform-runtime了,并且也不再需要在代碼中手動引入babel-polyfill了(但是還需要安裝,因為編譯后的代碼依賴了它),Babel 會在你使用到 ES2015+ 新特性時,自動添加 babel-polyfill 的引用,并且是 partial 級別的引用。
請注意: usage 的行為類似 babel-transform-runtime,不會造成全局污染,因此也會不會對類似 Array.prototype.includes() 進行 polyfill。