程式碼拆分
Parcel 支援開箱即用的零組態程式碼分割。這讓你可以將應用程式程式碼分割成獨立的套件,這些套件可以在需要時載入,進而縮小初始套件大小並加快載入時間。
程式碼分割由動態 import()
語法控制,其運作方式與一般 import
陳述式類似,但會傳回 Promise。這表示模組可以非同步載入。
使用動態載入
#以下範例說明如何使用動態載入在需要時載入應用程式的子頁面。
import("./pages/about").then(function (page) {
// Render page
page.render();
});
export function render() {
// Render the page
}
由於 import()
會傳回 Promise,因此你也可以使用 async/await 語法。
async function load() {
const page = await import("./pages/about");
// Render page
page.render();
}
load();
export function render() {
// Render the page
}
樹狀搖晃
#當 Parcel 可以判斷你使用動態載入模組的哪些匯出時,它會從該模組中樹狀搖晃未使用的匯出。這適用於靜態屬性存取或解構,並搭配 await
或 Promise .then
語法。
注意:對於 await
的情況,很遺憾地,只有在未轉譯掉 await
時才能移除未使用的匯出(例如,使用現代的 browserslist 組態)。
let { x: y } = await import("./b.js");
let ns = await import("./b.js");
console.log(ns.x);
import("./b.js").then((ns) => console.log(ns.x));
import("./b.js").then(({ x: y }) => console.log(y));
共用套件
#當應用程式的多個部分依賴於相同的共用模組時,這些模組會自動去重並封裝成獨立的套件。這讓常用的依賴項可以與應用程式程式碼並行載入,並由瀏覽器個別快取。
例如,如果您的應用程式有多個頁面,且這些頁面包含依賴於相同共用模組的 <script>
標籤,這些模組會拆分到「共用套件」中。如此一來,如果使用者從一個頁面導覽到另一個頁面,他們只需要下載該頁面的新程式碼,而不用下載頁面之間的共用相依性。
<!doctype html>
<div id="app"></div>
<script type="module" src="home.js"></script>
import { createRoot } from 'react-dom';
createRoot(app).render(<h1>Home</h1>, app);
<!doctype html>
<div id="app"></div>
<script type="module" src="profile.js"></script>
import { createRoot } from 'react-dom';
createRoot(app).render(<h1>Profile</h1>, app);
已編譯的 HTML
<!doctype html>
<div id="app"></div>
<script type="module" src="react-dom.23f6d9.js"></script>
<script type="module" src="home.fac9ed.js"></script>
<!doctype html>
<div id="app"></div>
<script type="module" src="react-dom.23f6d9.js"></script>
<script type="module" src="profile.9fc67e.js"></script>
在上述範例中,home.js
和 profile.js
都依賴於 react-dom
,因此會將其拆分到一個獨立的套件中,並透過在兩個 HTML 頁面中加入額外的 <script>
標籤,讓它們並行載入。
這也適用於應用程式中已使用動態 import()
進行程式碼拆分的不同區段。兩個動態匯入之間共用的相依性會拆分出來,並與動態匯入的模組並行載入。
組態
#預設情況下,Parcel 只有在共用模組達到一定大小門檻時才會建立共用套件。這樣可以避免拆分非常小的模組,以及產生額外的 HTTP 要求,即使使用 HTTP/2,這些要求也會造成負擔。如果模組小於門檻值,它會在各個頁面之間重複,而不是拆分。
Parcel 也有最大並行要求限制,以避免一次向瀏覽器發出太多要求而造成過載,如果達到此限制,它會重複模組。在建立共用套件時,會優先處理較大的模組,而非較小的模組。
預設情況下,這些參數已針對 HTTP/2 調整。但是,您可以調整這些選項,以提高或降低應用程式的參數。您可以透過設定專案根目錄中 package.json 中的 @parcel/bundler-default
鍵來執行此操作。
{
"@parcel/bundler-default": {
"minBundles": 1,
"minBundleSize": 3000,
"maxParallelRequests": 20
}
}
可用的選項如下
- minBundles – 若要拆分資產,它必須被超過
minBundles
個套件使用。 - minBundleSize – 若要建立共用套件,它必須至少有
minBundleSize
位元組大小(在縮小和樹狀搖晃之前)。 - maxParallelRequests – 為了防止過多同時要求而造成網路過載,這會確保最多有
maxParallelRequests
個同層級套件可以一起載入。 - http – 用於將上述值設定為針對 HTTP/1 或 HTTP/2 最佳化的預設值。請參閱下表以取得這些預設值。
http | minBundles | minBundleSize | maxParallelRequests |
---|---|---|---|
1 | 1 | 30000 | 6 |
2 (預設) | 1 | 20000 | 25 |
您可以在 web.dev 上閱讀更多關於此主題的資訊。
內部非同步套件
#如果模組在同一個套件中同步和非同步匯入,而非將它拆分到一個獨立的套件,則非同步相依性將會「內部化」。這表示它會和動態匯入保留在同一個套件中以避免重複,但會包裝在 Promise
中以保留語意。
因此,動態匯入只是一個相依性不需要同步的提示,並非保證會建立新的套件。
重複資料刪除
#如果動態匯入的模組具有在所有可能的祖先中都已經存在的相依性,則會刪除重複資料。例如,如果一個頁面匯入一個也由動態匯入的模組使用的函式庫,則該函式庫只會包含在父項中,因為它在執行階段已經在頁面上。
手動共用套件
#注意:手動共用套件目前為實驗性質,可能會變更。
預設情況下,Parcel 會自動將常用的模組拆分為「共用套件」,並在上述情況中建立套件。不過,在某些情況下,您可能想要明確指定套件中包含哪些內容,以及誰可以要求該套件。
這些情況包括但不限於...
- 從其他建置工具或套件管理程式將您的設定移植到 Parcel
- 減少 HTTP 要求,不重複資產,有利於過度擷取
- 過度擷取和整體載入較少的套件,可以改善測量結果,例如 互動時間,特別是對於非常大型的專案。
- 為特定路由或模組集建立最佳化的共用套件
手動共用套件可以在專案根目錄的 package.json
中指定。assets
屬性必須設定為 glob 清單。任何與這些 glob 相符的資產檔案路徑都將包含在手動共用套件中。
此範例建立一個供應商套件,其中包含從 manual.js
開始的圖表中所有 JS 資產,分成 3 個並行的 HTTP 要求。
{
"@parcel/bundler-default": {
"manualSharedBundles": [
{
"name": "vendor",
"root": "manual.js",
"assets": ["**/*"],
"types": ["js"],
"split": 3
},
],
},
}
完整的選項清單如下
- name (選用) - 將套件上的
manualSharedBundle
欄位設定為 <name>,這可以在自訂報告程式或命名器中讀取,以供開發用途 - root (選用) - 將 glob 的範圍縮小到指定的檔案。在上述範例中,glob
**/*
將符合manual.js
中的所有匯入 - assets (必填) - Parcel 要比對的 glob。符合 glob 的檔案將放入單一套件中,並在專案中進行重複資料刪除,除非另有指定。如果未指定
root
,Parcel 會嘗試在**全域**比對 glob。 - types (選用) - 將 glob 限制為僅比對特定類型。如果
root
檔案匯入多種類型(例如 JS 和 CSS),或者assets
glob 可以符合不同類型,則必須設定此欄位。套件只能包含相同類型的資產。- root 檔案可以包含多種類型的匯入。請務必在
manualSharedBundle
陣列中為每種類型新增一個物件。
- root 檔案可以包含多種類型的匯入。請務必在
- split (選用) - 將手動套件分成 x 個套件。
- 對於非常大的套件,將其分成多個並行的 HTTP 要求可以改善測量結果,例如 CHR(快取命中率),因為較小的套件會因特定變更而失效。
小心!
設定手動共用套件會覆寫 Parcel 通常執行的所有自動程式碼拆分,並可能導致意外的載入順序問題,因為它會對你的整個程式碼庫進行對應,包括 node_modules
。請注意你使用的 glob,每個檔案類型只指定 1 個套件,我們建議你指定一個根目錄檔案。