跳轉到主要內容
Manifest V3 的 service worker 經常會冷啟動:瀏覽器會在閒置約 30 秒後將它終止,並在下一個事件發生時重新啟動。每一 KB 你在 worker 最上層 import 進來的程式,都會在每次喚醒時被重新解析一次。如果你把打包好的 parser、wasm 執行階段或 AI SDK 放在 worker 進入點,那每一次 alarm、訊息與點擊都得付出這些成本。

動態 import() 可以在哪些地方使用

在打包工具介入之前,平台本身的規則如下:
Context執行階段的動態 import()
Service worker(背景)否,規範不允許
擴充功能頁面(popup、選項、新分頁、側邊面板)
Offscreen documents
Content scripts是,但需要多一個步驟
service worker 上的限制最常讓人意外:在任何瀏覽器中,平台層面都不支援在 service worker 裡使用動態 import()。在 worker 最上層使用靜態 import 語句沒問題(Extension.js 會將它們打包),但你無法把一個 chunk 的載入延後到某個事件發生時才進行。

模式 1:依介面切分,而不是依 chunk 切分

service worker 的職責是協調,而不是運算。請讓它的靜態 import 僅止於黏合性程式(路由訊息、註冊監聽器),任何吃資源的工作都搬到能夠延遲載入的介面去:
  • 跟 UI 相關的工作應該放在需要它的那個頁面。一個會格式化程式碼的 popup,就把 formatter import 在 popup 裡,而不是在 worker 裡。
  • 只在背景發生的吃資源工作(解析、編碼、推論),應該放到offscreen document — 按需建立、結束後關閉。worker 就保持為一個輕薄的訊息路由器。
background.ts
chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
  if (message.type === "parse-feed") {
    ensureOffscreen()
      .then(() =>
        chrome.runtime.sendMessage({ target: "offscreen", ...message }),
      )
      .then(sendResponse);
    return true;
  }
});
接著 offscreen 頁面就可以在第一次被要求時才 import() 那個大型函式庫,這樣成本只會在每個 document 的生命週期內付一次,而不是每次 worker 喚醒都付一次。

模式 2:在擴充功能頁面中延遲 import

在任何擴充功能頁面裡,一般的動態 import 都可以正常運作,打包工具也會自動把 chunk 切分出來:
popup.ts
button.addEventListener("click", async () => {
  const { highlight } = await import("./heavy/highlighter");
  output.innerHTML = highlight(input.value);
});
這裡沒有任何擴充功能專屬的細節:chunk 會被輸出到你的 build 結果中,從擴充功能自己的 origin 載入。

模式 3:在 content scripts 中延遲 import

Content scripts 是在頁面的環境中執行,因此它們延遲載入的 chunk 必須能被那個頁面抓取。需要兩個步驟:
  1. 透過 web_accessible_resources 公開這些 chunk 的路徑。
  2. 透過 chrome.runtime.getURL 來 import,讓 URL 解析到你的擴充功能 origin:
content.ts
async function loadAnalyzer() {
  const src = chrome.runtime.getURL("content_scripts/analyzer.js");
  return import(src);
}
對應的 manifest 區塊請參見 web_accessible_resources。如果沒設定,import 會因為網路錯誤而失敗,因為宿主頁面無法抓取那些沒有被明確公開的擴充功能檔案。

哪些東西絕對不要放進 worker

  • 任何跟 DOM 有關的東西(DOMParser、canvas、audio):worker 完全沒有 DOM,請改用 offscreen document。
  • 數 MB 大的 wasm:在 offscreen document 或額外頁面中實體化它,並把結果快取到 chrome.storage,這樣重啟時成本才會低。
  • 一次性的工具(匯入、遷移、匯出):放在 pages/ 底下的專屬頁面,可以讓它遠離每一條啟動路徑。

延伸閱讀