Babel的最新版本Babel 7 已經在Henry Zhu的不斷努力下發布了,他真的是全身心地投入到了Babel的開發中,而Babel對於前端界的貢獻也是有目共睹,沒有這個神奇的編譯器,前端界要落地ES6語法恐怕還要再等十年。
最近我在給自己團隊的UI組件庫升級到Babel 7,沒有想象中那麼難,但也有一些需要注意的問題,這裏分享一些升級的體會和經驗。
關於stage-x插件的廢棄
Babel 7的改動還是不少的,一個比較大的改動在於移除了之前的stage-x
插件,根據官方博客的解釋,stage-x
插件原本是對應於ECMA Script提案中的不同階段,每個階段有不同特性,而stage-x
插件事實上就是集合這個階段中幾種特性轉譯的插件,比如我們最經常看到的babel-preset-stage-0
,其實就是這樣的:
module.exports = {
presets: [
require("babel-preset-stage-1")
],
plugins: [
require("babel-plugin-transform-do-expressions"),
require("babel-plugin-transform-function-bind")
]
};
每個stage插件都會包含下一階段的所有插件,這就導致大家爲了能用上大多數特性,紛紛採用了babel-preset-stage-0
,React項目中,我們最經常看到的babelrc
配置是這樣的:
{
"presets": ["es2015", "react", "stage-0"]
}
然而,提案一直在變,如今是stage 0的特性,可能之後就進入到了stage 1,也可能之後直接被否決拋棄掉,並不會進入到ES規範中。那麼babel是不是應該更新這些stage插件呢?如果更新了,現階段大量前端項目、npm庫都在使用這個stage插件,會不會突然發現就編譯不了某個特性了呢?
到底應該遵循規範,還是應該遷就老項目做兼容呢?
最後Babel團隊做出來的決定是,廢棄掉stage-x
插件!這不僅僅是關乎上面這個問題,由於大家已經習慣了stage的配置,對於其中封裝的各個特性早已不再關心,廢除掉stage-x
插件,開發者就得加上自己需要的插件,每個插件對應一個提案中的特性,這樣項目中的配置也能更清晰。
另外,之前的命名也由@babel/plugin-transform-
改爲@babel/plugin-proposal-
,就是爲了強調這只是一個提案中的特性,並不能確保它會出現在下一代的ES規範中。
es2015 插件 -> env 插件
babel-preset-env
已經發布了一段時間,它相比es2015
可以更加靈活地配置,Babel 7宣佈廢棄babel-preset-es201x
而採用新的env插件也是理所當然,這個插件的配置不再贅述,可以參考官方文檔
說說babel-upgrade
爲了讓你更方便的升級到Babel 7,官方提供了一個工具babel-upgrade,對於已有的項目,只需要運行這樣一行命令就可以了:
npx babel-upgrade --write --install
但是這就是爲什麼我先寫了前面這兩節的原因,這個工具的本質其實就是把之前的es2015
換成env
,stage-x
換成各種proposal-xxx
,並且加上了@babel
作爲新的Babel 7生態統一使用的scope。如果之前的項目使用了stage-x
插件,就會多出大量的插件,其實這裏面大部分插件都是無需使用的,你可以根據項目中用到的特性適當刪減。
事實上,我最後項目中只使用了一個插件,babelrc配置如下:
{
"presets": [
[
"@babel/preset-env",
{
"modules": false
}
],
"@babel/preset-react"
],
"plugins": ["@babel/proposal-class-properties"]
}
說說babel-plugin-transform-class-properties
這個插件在React項目中十分常用,因爲我們經常需要將React組件類中的方法的this
綁定到組件本身,如果不用箭頭函數,我們就需要使用bind
將函數一個個綁定好,但如果可以使用箭頭函數在class字段中直接綁定的話,就非常方便了,即:
class Bork {
boundFunction = () => {
return this.state;
}
}
這樣,箭頭函數被當作成class的屬性來看待,this
也不會指向undefined
。
這個特性就需要babel-plugin-transform-class-properties來轉譯,這個插件在原來是包含在stage-2
裏面的,現在,就需要單獨引入。
當然其實這裏最好是引入@babel/plugin-proposal-class-properties,更加符合規範。
這個是屬於Class Field提案。