我猜很多同學和我一樣每次使用 Babel 的時候,必選的 preset 就是 ES2015。
然而就在最近,如果你再次安裝 babel-preset-es2015 時
1 |
npm install --save-dev babel-preset-es2015 |
你會發現有如下的 Deprecated警告(文字很歡樂):
babel-preset-es2015@6.24.1: We’re super ? excited that you’re trying to use ES2015 syntax, but instead of making more yearly presets ? , Babel now has a better preset that we recommend you use instead: npm install babel-preset-env –save-dev. preset-env without options will compile ES2015+ down to ES5 just like using all the presets together and thus is more future proof. It also allows you to target specific browsers so that Babel can do less work and you can ship native ES2015+ to user ? ! We are also in the process of releasing v7, so please give http://babeljs.io/blog/2017/09/12/planning-for-7.0 a read and help test it out in beta! Thanks so much for using Babel ?, please give us a follow on Twitter @babeljs for news on Babel, join http://slack.babeljs.io for discussion/development and help support the project at opencollective.com/babel
是的,在2017年第三季度我們終於要和 ES2015 preset 說再見了。
那麼你可能會問我們是要遷移到 ES2017 了嗎?事實上並非如此,babel-preset-es2017 只是增加了一些特性而已,且仍然需要安裝 ES2015。好了,不賣關子了,答案就是——
你好,babel-preset-env
Babel 的官網上在9月宣佈 ES2015 / ES2016/ ES2017 等等 ES20xx 時代的 presets 通通被廢棄(deprecated),取而代之的是 babel-preset-env,並且承諾它將成為“未來不會過時的(future-proof)”解決方案。
在過去,Babel 將 babel-preset-es2015 放在 babel/babel 的主倉庫中進行維護,而 babel-preset-env 則獨立為一級專案,這從某種程度上也顯示出 Babel 官方對這款 preset 的重視程度和更長遠的規劃。
如何遷移
為了節省你的閱讀時間,我先給出一個如何升級的簡單版:
首先解除安裝原來的 preset,然後安裝 babel-preset-env:
1 2 |
npm uninstall --save-dev babel-preset-es2015 npm install --save-dev babel-preset-env@next |
接下來將你的 .babelrc 檔案中“es2015”修改“env”:
1 2 3 4 |
{ "presets": [ "env" ], ... } |
好了,恭喜你,就這麼簡單,你已經可以與 ES2015+ 保持更新了!
更進一步
在 babel-preset-env 的官方說明中提到這是一款可以“自動”決定載入哪些外掛和 polyfill 的 preset,既然是叫“env”,那麼一定是可以由開發者決定編譯目標處於什麼樣的執行環境。
targets 選項
通過 targets 指定需要相容的瀏覽器型別和版本(採用 ai/browserslist 查詢語法 ):
1 2 3 4 5 6 7 8 9 |
{ "presets": [ ["env", { "targets": { "browsers": ["last 2 versions", "safari >= 7"] } }] ] } |
換句話說,你可以通過指定更高的瀏覽器版本來減少外掛和 polyfill 的程式碼量,並且直接使用原生 ES6 的新特性,特別適合 Electron 及移動端 App 或者那些已指定了瀏覽器的內網應用程式。例如,將瀏覽器設為 Chrome 較高的版本,Promise、Map、Set 等內建類均不會被 polyfill,而同時 class 等新語法也不會被 Babel 轉譯,轉而使用 V8 自帶的 ES6 Class。
如果你是用來開發 Node.js 應用,也同樣可以指定 Node 的版本:
1 2 3 4 5 6 7 8 9 |
{ "presets": [ ["env", { "targets": { "node": "6.10" } }] ] } |
為了方便,你也可以直接寫成 “node”: “current”,將自動採用你當前用來執行 Babel 的 Node.js 版本。
同時也可以在 targets 中指定 browsers 選項。
目前 targets 中支援了幾乎所有主流執行時環境,其中就包括了 IE、Chrome、Firefox、Opera、Edge、Safari、iOS Safari、Android、Node 和 Electron 等。
modules 選項
該選項與過去一致,用來指定模組化方式,支援 AMD、UMD、SystemJS、CommonJS 等。當然在 Webpack 2/3 的時代,推薦將 modules 設定為 false,即交由 Webpack 來處理模組化,通過其 TreeShaking 特性將有效減少打包出來的 JS 檔案大小:
1 2 3 4 5 6 7 8 |
{ "presets": [ ["env", { modules: false, ... }] ] } |
從 Webpack 2 開始,已自動啟用對 Native Import 的支援,因此無需對 Webpack 進行額外設定,詳情請參考我的另一個答案Henry Li:ECMAScript 6 的模組相比 CommonJS 的require (…)有什麼優點?
useBuiltIns 選項與 Polyfill
請注意:以下為 2.0-beta 的功能
這是一個關於 Polyfill 的選項,個人認為這是此次遷移後帶來的最大便利,當然首先你仍然需要額外安裝 babel-polyfill(是的,你不再需要額外的 transform)
1 |
npm install babel-polyfill@next --save |
當 useBuiltIns 設定為 usage 時,Babel 會在你使用到 ES2015+ 新特性時,自動新增 babel-polyfill 的引用,並且是 partial 級別的引用。
請注意: usage 的行為類似 babel-transform-runtime,不會造成全域性汙染,因此也會不會對類似 Array.prototype.includes() 進行 polyfill。
例如:
1 2 |
const promise = new Promise(); const map = new Map(); |
會被轉譯為:
1 2 3 4 5 |
import "babel-polyfill/lib/core-js/modules/es6.map"; import "babel-polyfill/lib/core-js/modules/es6.promise"; var promise = new Promise(); var map = new Map(); |
很多人習慣於在 vendor 中一次性引入 babel-polyfill,在過去這將導致整個 babel-polyfill 包被打包到 vendor 中,在方便開發的同時失去了靈活性,而現在你可以將 useBuiltIns 設定為 entry,Babel 會自動進行優化:
例如:
vendor.js :
1 |
import 'babel-polyfill'; |
index.js:
1 2 |
const promise = new Promise(); const map = new Map(); |
最終 vendor.js 會被轉譯為:
1 2 |
import "babel-polyfill/core-js/modules/es6.map"; import "babel-polyfill/core-js/modules/es6.promise"; |
怎麼樣?是不是超級“智慧”!
再見,babel-preset-es2015
現在,我們可以放心的說,是時候和 babel-preset-es2015 告別了。
babel-preset-env 目前正在不斷積極更新中,更多的 babel-preset-env 選項請參見 babel/babel-preset-env。