安裝babel不就是為了使用es的所有新特性么,為什麼還要弄個插件配置來說明我要用哪些新特性?

搞不懂為什麼babel不設計成無需插件配置,裝上就能使用es所用新特性?


因為 babel 的存在不只是為了『使用 es 的所有新特性』。它需要考慮如下問題:

  1. 如何處理尚未成為標準的提案?

    建議你先了解一下 ECMAScript 的制定流程 (參考: http://wwsun.github.io/posts/new-in-es2016.html),除了已經正式納入規範 (ES2015/6/7) 的特性,還有許多處於不同討論階段的特性提案 (stage 1/2/3/4)。這些討論中的特性嚴格來說還不算是標準,尤其是 stage 1/2 的特性,完全有可能被改動甚至是撤銷提案。因此從 babel 的角度來說,顯然不能夠默認啟用這些特性,而需要有可配置的選項讓用戶自行衡量風險,決定是否使用。

  2. 如何針對不同平台的支持情況,減少無用特性的編譯。

    默認目標通常是 ES5,但其實每個特性都有對應的性能開銷,babel 本來速度就不是很快,如果能針對目標平台減少需要處理的特性,可以提高編譯效率,也可以盡量使用平台原生的 ES 特性。比如如果只針對最新的 Chrome,大部分插件都是不需要的。有時候你可能只需要一兩個特定的插件,比如 syntax-dynamic-import。有時候你可能需要保留一些 ES 特性不編譯,比如使用 webpack 2 的時候保留 ES modules 語法不編譯為 CommonJS。這些都決定了可配置性是必需的。當然手動配置肯定很麻煩,這也是為什麼現在有了 babel-preset-env,可以自動根據目標平台分析需要用哪些插件。

  3. 作為一個編譯工具鏈,給予用戶實驗、甚至是實現非標準的語言擴展的能力。

    Babel 的一個重要意義就在於能夠讓用戶提前使用尚未成為標準的語言特性,從而為標準本身的制定提供實踐中才能獲得的反饋。一個提案靠不靠譜,該不該成為標準?先做個插件出來用到項目里感受一下,比空口討論靠譜得多。

    至於非標準擴展,比如 JSX 並非 ES 標準,但其編譯就是完全依賴 Babel 的可配置的插件能力才得以實現的。

    另外,babel 作為一個工具鏈還可以有很多其他用途,比如用來進行編譯時的性能優化、測試覆蓋率的 instrumentation 等等。

綜上,插件化是 babel 存在的核心價值,對於配置的問題,它的答案是 preset;對於題主的需求,用 babel-preset-env 的默認配置即可。另外如果沒有以上這些可配置性方面的需求,Buble (https://buble.surge.sh) 也是一個可以考慮的選擇,但 Buble 並不追求與規範 100% 的一致性,是否適合你,需要你自行判斷。


事實上,Babel 正在嘗試的改進方向就是這樣:babel/babel-preset-env

通過 babel-preset-env 這個工具,就自動包含了當前所有 ES 特性:

{
"presets": ["env"]
}

然後也可以描述性地說明需要支持的平台,就能自動配置相應的插件(或者說去除不必要的插件):

{
"presets": [
["env", {
"targets": {
"browsers": ["last 2 versions", "safari &>= 7"]
}
}]
]
}

這樣,如果我們支持的瀏覽器較新,那麼很多插件根本就不需要用到,既能保證瀏覽器兼容性,也能保證最佳的編譯速度和最小的 Polyfill 體積。

不過,需要特別注意的是,這裡僅僅針對的是當前的 ES 特性,而語言提案並不是 ES 特性,因此也不會被包含進來。甚至還有不屬於語言提案的私有語言擴展,當然也不可能默認包含。

所以如果題主需要的是 ES 語言特性的話,那這個目標應當可以認為已經實現了,而如果目標是 ((ES 語言特性)的提案)的話,那就要麻煩很多,這是由 ES 的處理流程(經由 TC39)所決定的,一個形象生動的版本是:

Stage 0 is "i"ve got a crazy idea",
stage 1 is "this idea might not be stupid",
stage 2 is "let"s use polyfills and transpilers to play with it",
stage 3 is "let"s let browsers implement it and see how it goes",
stage 4 is "now it"s javascript".

出自 Rename stage presets to indicate the danger of using them · Issue #4914 · babel/babel,一個關於 Stage Preset 的改名建議。

簡單地說,到達 Stage 4 之前,這些提案都是會被修改的,甚至是可能被廢棄的。所以上面有建議把對應 preset 的名稱改成:

  • babel-preset-extremely-dangerous-stage-0
  • babel-preset-dangerous-stage-1
  • babel-preset-risky-stage-2
  • babel-preset-solid-stage-3
  • babel-preset-frozen-stage-4

這樣有助於用戶自行評估風險。最近的一些比較大的風險類似於:

  • 已經到達 Stage 3 的 SIMD(tc39/ecmascript_simd)被幹掉。不過由於 SIMD 是純 API,不涉及新語法,因此和 Babel 關係不大。
  • Class Property Decorator(tc39/proposal-decorators)從 Stage 0 到 Stage 2 的過程中語法和語義都發生的變化,這樣就到達了一個很尷尬的境地,目前現有的所有 Decorator 實現都是錯誤的,等實現和新規範同步後,以前所有使用 Decorator 的代碼都會失效。而對於 Babel 插件而言這也是一個重大挑戰,一旦符合標準,就必然會破壞現有代碼的兼容性;但也不可能永遠不支持新提案,否則 Stage 就一直上不去。
  • Stage 2 的 Public Class Property(tc39/proposal-class-public-fields)和 Stage 2 的 Private Class Fields(tc39/proposal-private-fields)合併為新的 Class Fields 提案(tc39/proposal-class-fields)。雖然合併本身並沒有修改提案內容,但是原先可以單獨使用的特性現在必須要一起使用了,也算是一種 Breaking Change。
  • Stage 3 的 Async Generator(tc39/proposal-async-iteration) 中 yield await 併入 yield(Move the awaiting (back) into yield by domenic · Pull Request #102 · tc39/proposal-async-iteration)。這種語義上的小變化也會導致編譯方式的改變,以前的某些 Edge Case 的代碼可能會被破壞。
  • Stage 3 的 Spread Property(tc39/proposal-object-rest-spread)中對對象字面值的解構被禁止了,也就是說不能再寫 { ...{ a: 1, b: 2 }, c: 3 } 這樣的代碼。雖然正常人都不會這麼寫,但不排除有人非要這麼寫然後引起代碼的不兼容。
  • ...

類似的問題可能還會越來越多,所以要使用語言提案的話,風險是由自己所承擔的,Babel 並不為此負責。此外,一些插件本身就是相互矛盾的,比如各種框架自己實現的 JSX Transform、進行類型檢查的 Flow 和 TypeScript(WIP,【RPU-A】Babel 即將增加 TypeScript 支持),邏輯上就不可能全部引入。

所以,如果需要使用不屬於 ES 特性的插件,當然還是得自行指定。

另外,對於語言提案部分,也有另一個嘗試改進的討論:

廢除所有 Stage Preset 的存在,自行聲明每個需要使用的非標準特性(Revamping stage plugins (Removing the stage-x presets) · Issue #4955 · babel/babel)。

這個是合理的,每個提案的演進本身就是獨立的,只是碰巧在某一時間可能共同處於某一狀態,就好比設立「月薪 5000 聯誼會」、「月薪 6000 聯誼會」、「月薪 7000 聯誼會」等等。可能別人只是拿著零花錢的小學生,過兩天就退會了,跑到別的級別去了。碰巧在某個月的月薪相同其實並沒有多大的共性,為此專門設立一個集合也並不非常合理。

這個改進應用後,將對當前插件機制的版本化方案起到很大幫助。

在今年(2017)5 月份的 TC39 會議中,也專門討論過 Babel 未來方向的問題,詳情可以參考:Presentation on Babel by hzoo · Pull Request #235 · tc39/agendas,hzoo/role-of-babel-in-js。


Babel的作用不只是轉譯ES代碼,理論上它可以轉譯一切代碼,你可以發明一個新的語言來讓Babel轉譯成JavaScript,當然,最大的好處,是有了Babel可以無視標準委員會的慢節奏,提前把一些人民喜聞樂見的語法拿來用,呵呵。

Babel目前這種默認什麼都不轉譯,只有配置了plugin或preset才真幹事的方式挺好,架構上更清晰,Babel的核心部分也可居於一個中立地位,隨便plugin開發者擴展功能。


首先es就沒有所有特性這個概念


事實上最初版本的 babel 就是你說的那樣,只是後來發現應用範圍越來越廣,從最初的轉譯工具演變成了平台,為了很好的靈活性和適應不同的需求,才採用了插件的形式。名字也從 6to5 改成了 babel


如果領導讓實現一個攻擊地球的方法,初級程序員直接寫了一個方法叫做attackEarth.然而高級程序員會寫個attackStar方法,然後把地球作為參數傳過去。


因為你加入的太遲了


env是個好東西啊···而且es各種提案,不定哪天就死幾個,哪天又多幾個。為了所有特性不是作死么


1.留給開發者一個可選餘地

2.為後續新特性的靈活添加做準備

這樣看,平台型?插件機制 是不是更合理?


如果把 babel 理解成一個 「從 JavaScript 的一個變種編譯到另一個變種」 的框架的話,沒有插件機制、只支持現有的ES標準才比較奇怪吧。

假設要支持若干年後的新ES,就只需要發布統一制式的相關插件就行了,豈不美哉?

而且在 「babel官方」 來不及開發所有的變種支持的情況下,動用社區的力量,讓大家一起給 babel 的支持作出貢獻不也很好嘛?還能讓它支持某些 「只屬於自己的 JavaScript 變種」。

不管怎麼說,babel 的插件機制都是「一件大快所有人心的大好事」。


推薦閱讀:

mock,前端團隊有5-6人,大家如何共用一套mock數據?
函數作為React組件的方法時, 箭頭函數和普通函數的區別是什麼?
如何實現 Babel 編譯器?

TAG:前端開發 | JavaScript | ECMAScript2015 | Babel |