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

Houssein Djirdeh
Houssein Djirdeh

在所有主要瀏覽器上順利運作的網站,是開放網路生態系統的核心原則。不過,這表示您必須額外確保所編寫的所有程式碼,都支援您打算鎖定的每個瀏覽器。如要使用新的 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 的審查。