為新型瀏覽器提供新程式碼,加快網頁載入速度

建構在所有主要瀏覽器上都能順利運作的網站,是開放式網路生態系統的核心宗旨。不過,這表示您必須額外進行工作,確保您編寫的所有程式碼都能在您打算指定的每個瀏覽器中運作。如果您想使用新的 JavaScript 語言功能,就必須將這些功能轉譯為回溯相容格式,以便在尚未支援這些功能的瀏覽器中使用。

Babel 是最常用的工具,可將包含較新語法的程式碼編譯為不同瀏覽器和環境 (例如 Node) 可理解的程式碼。本指南假設您正在使用 Babel,因此如果您尚未按照設定操作說明將 Babel 納入應用程式,請務必按照該說明進行操作。如果您在應用程式中使用 webpack 做為模組捆綁器,請在 Build Systems 中選取 webpack

如要使用 Babel 僅轉譯使用者所需的內容,您需要:

  1. 找出要指定的瀏覽器。
  2. 請搭配適當的瀏覽器目標使用 @babel/preset-env
  3. 使用 <script type="module"> 停止將轉譯過的程式碼傳送至不需要的瀏覽器。

找出要指定的瀏覽器

開始修改應用程式中程式碼的轉譯方式前,您必須先找出哪些瀏覽器會存取您的應用程式。請分析使用者目前使用的瀏覽器,以及您打算指定的瀏覽器,以便做出明智的決定。

使用 @babel/preset-env

轉譯程式碼通常會產生比原始形式更大的檔案。盡量減少編譯作業,即可縮減組合大小,進而改善網頁效能。

與其加入特定外掛程式,以便選擇性編譯您使用的特定語言功能,不如使用 Babel 提供的多個預設值,將外掛程式打包在一起。使用 @babel/preset-env,只納入您要指定瀏覽器所需的轉換和 polyfill。

在 Babel 設定檔 .babelrcpresets 陣列中加入 @babel/preset-env

{
 "presets": [
   [
     "@babel/preset-env",
     {
       "targets": ">0.25%"
     }
   ]
 ]
}

使用 targets 欄位,在 browsers 欄位中新增適當的查詢,指定要納入哪些瀏覽器版本。@babel/preset-env 會整合 browserslist,這是在不同工具之間共用的開放原始碼設定,用於指定瀏覽器。如需相容查詢的完整清單,請參閱 browserslist 說明文件。另一個選項是使用 .browserslistrc 檔案,列出您要指定的環境。

">0.25%" 值會指示 Babel 只納入所需的轉換作業,以支援全球使用率超過 0.25% 的瀏覽器。這樣可確保套件不會包含不必要的轉譯程式碼,以免影響使用者瀏覽器的極少數使用者。

在大多數情況下,這比使用下列設定更為理想:

  "targets": "last 2 versions"

"last 2 versions" 值會為每個瀏覽器的最後兩個版本轉譯程式碼,這表示系統會為 Internet Explorer 等已停用的瀏覽器提供支援。如果您不打算使用這些瀏覽器存取應用程式,這可能會不必要地增加套件的大小。

最終,您應選取適當的查詢組合,只指定符合需求的瀏覽器。

啟用現代化錯誤修正

@babel/preset-env 會將多個 JavaScript 語法功能分組為集合,並根據指定的目標瀏覽器啟用/停用這些功能。雖然這項做法運作良好,但如果指定的瀏覽器只包含單一功能的錯誤,整個語法功能集就會轉換。這通常會導致轉換的程式碼比必要的還要多。

@babel/preset-env 中的bugfixes 選項原本是獨立預設值,可解決這項問題,方法是將在部分瀏覽器中無法運作的新型語法,轉換為在這些瀏覽器中可正常運作的最接近等效語法。結果幾乎與新式程式碼相同,只是經過一些小語法調整,確保在所有目標瀏覽器中皆可相容。如要使用這項最佳化功能,請務必安裝 @babel/preset-env 7.10 以上版本,然後將 bugfixes 屬性設為 true

{
 "presets": [
   [
     "@babel/preset-env",
     {
       "bugfixes": true
     }
   ]
 ]
}

在 Babel 8 中,bugfixes 選項預設為啟用。

使用 <script type="module">

JavaScript 模組 (或稱 ES 模組) 是所有主要瀏覽器支援的相對較新功能。您可以使用模組建立可從其他模組匯入及匯出的指令碼,但也可以搭配 @babel/preset-env 使用,只針對支援這些指令碼的瀏覽器。

請勿查詢特定瀏覽器版本或市占率,而是考慮在 .babelrc 檔案的 targets 欄位中指定 "esmodules" : true

{
   "presets":[
      [
         "@babel/preset-env",
         {
            "targets":{
               "esmodules": true
            }
         }
      ]
   ]
}

在支援 JavaScript 模組的環境中,許多以 Babel 編譯的新 ECMAScript 功能都已獲得支援。因此,您可以簡化確保只在實際需要的瀏覽器中使用轉譯程式碼的程序。

支援模組的瀏覽器會忽略帶有 nomodule 屬性的指令碼。相反地,不支援模組的瀏覽器會忽略含有 type="module" 的腳本元素。也就是說,您可以加入模組和已編譯的備用項。

理想情況下,應用程式的兩個版本指令碼應如下所示:

  <script type="module" src="main.mjs"></script>
  <script nomodule src="compiled.js" defer></script>

支援模組的瀏覽器會擷取及執行 main.mjs,並忽略 compiled.js。不支援模組的瀏覽器則會反過來做。

如果您使用 webpack,可以在設定中為應用程式的兩個不同版本設定不同的目標:

  • 僅適用於支援模組的瀏覽器。
  • 這個版本包含可在任何舊版瀏覽器中運作的已編譯指令碼。由於轉譯需要支援更多瀏覽器,因此檔案大小會較大。

感謝 Connor Clark 和 Jason Miller 提供意見。