我們?yōu)槭裁磿?huì)使用babel非凌?因?yàn)槲覀儠?huì)使用很多es的新語(yǔ)法荆针。但瀏覽器的支持卻還不完善。所以我們只能使用babel編譯器來幫助我們航背。
如果我們還使用了webpack的話玖媚,我們會(huì)在webpack中增加babel-loader
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test')]
},
在babel5的時(shí)代,babel屬于全家桶型今魔,只要安裝babel就會(huì)安裝babel相關(guān)的所有工具,
即裝即用吟宦。
但是到了babel6涩维,具體有以下幾點(diǎn)變更:
移除babel全家桶安裝,拆分為單獨(dú)模塊激挪,例如:babel-core辰狡、babel-cli、babel-node垄分、babel-polyfill等宛篇;
使用babel的會(huì)自動(dòng)識(shí)別.babelrc文件。
該文件用來設(shè)置轉(zhuǎn)碼規(guī)則和插件薄湿,基本格式如下叫倍。
{
"presets": [], // 設(shè)定轉(zhuǎn)碼規(guī)則
"plugins": [], //
}
plugin:,插件豺瘤,通過配置不同的插件才能告訴babel吆倦,我們的代碼中有哪些是需要轉(zhuǎn)譯的。
preset:babel5會(huì)默認(rèn)轉(zhuǎn)譯ES6和jsx語(yǔ)法坐求,babel6轉(zhuǎn)譯的語(yǔ)法都要在perset中配置,preset簡(jiǎn)單說就是一系列plugin包的使用。
為什么我們經(jīng)常會(huì)看到Stage 2這種插件须妻?
ES即ECMAScrip仔蝌。被納入到ES標(biāo)準(zhǔn)的語(yǔ)法必須要經(jīng)過如下五個(gè)階段:
Stage 0: strawman
Stage 1: proposal
Stage 2: draft - 必須包含2個(gè)實(shí)驗(yàn)性的具體實(shí)現(xiàn),其中一個(gè)可以是用轉(zhuǎn)譯器實(shí)現(xiàn)的荒吏,例如Babel敛惊。
Stage 3: candidate - 至少要有2個(gè)符合規(guī)范的具體實(shí)現(xiàn)。
Stage 4: finished
除了已經(jīng)正式納入規(guī)范 (ES2015/6/7) 的特性绰更,還有許多處于不同討論階段的特性提案 (stage 1/2/3/4)瞧挤。這些討論中的特性嚴(yán)格來說還不算是標(biāo)準(zhǔn),尤其是 stage 1/2 的特性儡湾,完全有可能被改動(dòng)甚至是撤銷提案皿伺。因此從 babel 的角度來說,顯然不能夠默認(rèn)啟用這些特性盒粮,而需要有可配置的選項(xiàng)讓用戶自行衡量風(fēng)險(xiǎn),決定是否使用奠滑。
那么我們?nèi)绾闻袛辔覀冃枰褂玫膕tage是哪一個(gè)呢丹皱?
在TC39的提案中,有對(duì)應(yīng)的一個(gè)詳細(xì)的列表表明哪種特性處于哪個(gè)階段:處于哪個(gè)階段
所以我們經(jīng)常會(huì)看到"stage-2"宋税。
transform-runtime VS babel-polyfill
為什么需要 babel-polyfill摊崭?因?yàn)閎abel的轉(zhuǎn)譯只是語(yǔ)法層次的轉(zhuǎn)譯,例如箭頭函數(shù)杰赛、解構(gòu)賦值呢簸、class,對(duì)一些新增api以及全局函數(shù)(例如:Promise)無(wú)法進(jìn)行轉(zhuǎn)譯乏屯,這個(gè)時(shí)候就需要在代碼中引入babel-polyfill根时,讓代碼完美支持ES6+環(huán)境。但很多時(shí)候我們并不會(huì)使用所有ES6+語(yǔ)法辰晕,全局添加所有墊片肯定會(huì)讓我們的代碼量上升蛤迎,之后會(huì)介紹其他添加墊片的方式。
那我們可以用到那個(gè)語(yǔ)法或者api增加哪個(gè)對(duì)應(yīng)的插件呀含友。
{
"plugins": [
"transform-es2015-arrow-functions", //轉(zhuǎn)譯箭頭函數(shù)
"transform-es2015-classes", //轉(zhuǎn)譯class語(yǔ)法
"transform-es2015-spread", //轉(zhuǎn)譯數(shù)組解構(gòu)
"transform-es2015-for-of" //轉(zhuǎn)譯for-of
]
}
這樣有個(gè)問題替裆。這種通過transform添加的polyfill只會(huì)引入到當(dāng)前模塊中,試想實(shí)際開發(fā)中存在多個(gè)模塊使用同一個(gè)api窘问,每個(gè)模塊都引入相同的polyfill辆童,大量重復(fù)的代碼出現(xiàn)在項(xiàng)目中,這肯定是一種災(zāi)難惠赫。另外一個(gè)個(gè)的引入需要polyfill的transform挺麻煩的把鉴,而且不能保證手動(dòng)引入的transform一定正確。所以我們使用transform-runtime
比較transform-runtime與babel-polyfill引入墊片的差異:
- 使用runtime是按需引入儿咱,需要用到哪些polyfill纸镊,runtime就自動(dòng)幫你引入哪些倍阐,不需要再手動(dòng)一個(gè)個(gè)的去配置plugins,只是引入的polyfill不是全局性的逗威,有些局限性峰搪。而且runtime引入的polyfill不會(huì)改寫一些實(shí)例方法,比如Object和Array原型鏈上的方法凯旭,像前面提到的Array.protype.includes概耻。
- babel-polyfill就能解決runtime的那些問題,它的墊片是全局的罐呼,而且全能鞠柄,基本上ES6中要用到的polyfill在babel-polyfill中都有,它提供了一個(gè)完整的ES6+的環(huán)境嫉柴。babel官方建議只要不在意babel-polyfill的體積厌杜,最好進(jìn)行全局引入,因?yàn)檫@是最穩(wěn)妥的方式计螺。
- 一般的建議是開發(fā)一些框架或者庫(kù)的時(shí)候使用不會(huì)污染全局作用域的babel-runtime夯尽,而開發(fā)web應(yīng)用的時(shí)候可以全局引入babel-polyfill避免一些不必要的錯(cuò)誤,而且大型web應(yīng)用中全局引入babel-polyfill可能還會(huì)減少你打包后的文件體積(相比起各個(gè)模塊引入重復(fù)的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
來達(dá)到按需引入的目的茫叭,也就是說不再需要transform-runtime
了,并且也不再需要在代碼中手動(dòng)引入babel-polyfill
了(但是還需要安裝半等,因?yàn)榫幾g后的代碼依賴了它)揍愁,Babel 會(huì)在你使用到 ES2015+ 新特性時(shí),自動(dòng)添加 babel-polyfill 的引用杀饵,并且是 partial 級(jí)別的引用莽囤。
請(qǐng)注意: usage 的行為類似 babel-transform-runtime,不會(huì)造成全局污染切距,因此也會(huì)不會(huì)對(duì)類似 Array.prototype.includes() 進(jìn)行 polyfill朽缎。