剛接觸bable的同學會犯一個錯誤,認為在使用了Babel后就可以暢快的使用 es2015 了,事實上Babel只能轉換語法(如箭頭函數、let、const、class等),像Promise 、Async、Object.assign、Array.find()等api是依賴瀏覽器實現的,想在不支持的瀏覽器上使用新的API,需要采用Polyfill技術,實現Polyfill有多種方式,方式對比請點我。
Babel 推薦使用 @babel/preset-env 套件來處理轉譯需求。顧名思義,preset 即“預制套件”,包含了各種可能用到的轉譯工具。
之前的以年份為准的 preset 已經廢棄了,現在統一用這個總包。同時,babel 已經放棄開發 stage-* 包,以后的轉譯組件都只會放進 preset-env 包里。
@babel/preset-env默認會支持stage4的特性轉換(當然是針對@babel/preset-env當前版本發布年份的stage4提案)。
一、重要參數
1. target
@babel/preset-env 支持一些參數,用來處理哪些 feature 要轉譯,哪些不要。其中比較重要的是 targets
,用來指定目標環境。targets
使用 browserslist 來篩選瀏環境,這樣我們就不需要指定所有瀏覽器版本,而可以使用類似 last 2 versions
這樣的描述。具體怎寫,可以看文檔,這里不再贅述。
如果你想知道自己配置的是否合適,可以在倉庫目錄下執行 npx browserslist
,列出所有目標瀏覽器。
Babel 官方建議我們把 targets
的內容保存到 .browserslistrc文件中
或者 package.json
里增加一個browserslist節點,不然除了babel外,其他的工具,例如browserslist、post-css等無法從 babel 配置文件里讀取配置。
2. useBuiltIns
接下來,我們可以配置 useBuiltIns
,這個屬性決定是否引入 polyfill。它有三個可選值:
false
,不引入,或者說,Babel 編譯結果不引入。把引入的位置、引入哪些 polyfill 交給用戶處理。
entry, 開發者
在核心入口文件中使用 import '@babel/polyfill'
語句引入,其實並不理想,因為大部分瀏覽器不需要這些。
usage,
即“按需引用”。如果目標瀏覽器(從target中知道目標瀏覽器)不支持需要的 feature,那么就自動引入 polyfill,不然的話就不引用。由於目前的打包工具越發智能,隨着 tree shaking 的完善,這樣可以最低限度引入 polyfill。
3. corejs
core-js 目前最新版本是 3.0.1,關於 v3 和 v2 的對比,大家可以看這篇博文:https://github.com/zloirock/core-js/blob/master/docs/2019-03-19-core-js-3-babel-and-a-look-into-the-future.md。這里簡單總結一下,core-js 2 封版於 1.5 年之前,所以里面只有對 1.5 年之前 feature 的 polyfill,最近 1.5 年新增的 feature 都不支持,也就存在因為新功能沒有 polyfill 於是在舊瀏覽器里失敗的風險。
所以我們應當升級到最新版,npm i core-js@3 -D
然后修改 babel 配置:
{ "presets": [ [ "@babel/preset-env", { "targets": "> 5%", "useBuiltIns": "usage", "corejs": 3 } ] ] }
此選項僅在與useBuiltIns:usage或useBuiltIns:entry一起使用時有效,並確保@babel/preset env為您的核心js版本注入正確的導入。
默認情況下,corejs只會使用stage2及更高階段的特性:如果要使用stage-1(proposal)的polyfill,有三個不同的選項 :
當使用useBuiltIns:“entry”時,可以直接導入一個建議polyfill:import“core js/propositions/string replace all”。
使用useBuiltIns:"usage"時:“用法”有兩種不同的選擇:
將shippedprovals選項設置為true。這將使polyfills和proposition轉換成為可能,這些建議已經在瀏覽器中發布了一段時間。
使用corejs:{version:3,propositions:true}。這將使核心js支持的每一個提案都能實現多元化。
備注: TC39 將提案分為以下幾個階段:
stage0 strawman
任何討論、想法、改變或者還沒加到提案的特性都在這個階段。只有TC39成員可以提交。
stage1 proposal
(1)產出一個正式的提案。 (2)發現潛在的問題,例如與其他特性的關系,實現難題。 (3)提案包括詳細的API描述,使用例子,以及關於相關的語義和算法。
stage2 draft
(1)提供一個初始的草案規范,與最終標准中包含的特性不會有太大差別。草案之后,原則上只接受增量修改。 (2)開始實驗如何實現,實現形式包括polyfill, 實現引擎(提供草案執行本地支持),或者編譯轉換(例如babel)
stage3 candidate
(1)候選階段,獲得具體實現和用戶的反饋。此后,只有在實現和使用過程中出現了重大問題才會修改。 (1)規范文檔必須是完整的,評審人和ECMAScript的編輯要在規范上簽字。 (2)至少要在一個瀏覽器中實現,提供polyfill或者babel插件。
stage4 finished
(1)已經准備就緒,該特性會出現在下個版本的ECMAScript規范之中。。 (2)需要通過有2個獨立的實現並通過驗收測試,以獲取使用過程中的重要實踐經驗。
有關詳細信息,請務必查看 current TC39 proposals 及其 process document。
二、@babel/polyfill
@babel/polyfill 是對 core-js 的封裝,引入該庫時,實際上是引用了 core-js 的內容和生成器(regenerator-runtime)。 v7.4 之后,這個倉庫就被廢棄了,希要用戶自己選擇使用哪個兼容庫。
換言之,以前是這么引用的:
import "@babel/polyfill";
現在需要:
import "core-js/stable";
import "regenerator-runtime/runtime";
對於絕大部分情況,使用 @babel/preset-env + useBuiltIns: 'usage'
仍然是最好的選則。
三、babel體系化教程
這個博文講得非常好,完整並且成體系,建議閱讀