Service Worker 中的 ES 模組

是 importScripts() 的新型替代方案。

背景

目前,ES 模組一直是開發人員最喜歡的一種。除了其他許多好處外,這些程式庫也提供通用模組格式的承諾,也就是可以發布一次共用的程式碼,並在瀏覽器和替代執行階段 (例如 Node.js) 中執行。雖然所有新式瀏覽器都提供部分 ES 模組支援,但並非所有新式瀏覽器都支援可執行程式碼的「所有位置」。具體來說,在瀏覽器的服務工作站中匯入 ES 模組的支援功能,已經擴大支援範圍。

本文將詳細說明在常見的瀏覽器中,服務工作站目前對 ES 模組支援的狀態,以及應避免的困難,以及運送回溯相容的 Service Worker 程式碼的最佳做法。

用途

Service Worker 內的 ES 模組理想用途,是載入與其他支援 ES 模組的其他執行階段共用的新型程式庫或設定程式碼。

嘗試在 ES 模組之前使用較舊的「通用」模組格式 (例如包含不需要的樣板的 UMD) 共用程式碼,以及編寫對全域公開變數進行變更的程式碼。

透過 ES 模組匯入的指令碼如果內容有所變更,且與 importScripts()行為相符,即可觸發 Service Worker 更新流程。

目前限制

僅限靜態匯入

您可以透過下列兩種方式匯入 ES 模組:使用 import ... from '...' 語法靜態匯入,或使用 import() 方法動態匯入。在 Service Worker 內,目前僅支援靜態語法。

這項限制類似於針對 importScripts() 用量提出的類似限制。對 importScripts() 的動態呼叫無法在 Service Worker 中運作,且所有在本質上同步的 importScripts() 呼叫都必須在 Service Worker 完成 install 階段前完成。這項限制可確保瀏覽器在安裝期間,瞭解服務工作站實作所需的所有 JavaScript 程式碼,並且能夠以隱含方式快取。

最終可能會解除這項限制,並允許動態 ES 模組匯入。目前,請確保您在 Service Worker 中只使用靜態語法。

其他員工呢?

支援「專屬」工作站中的 ES 模組 (以 new Worker('...', {type: 'module'}) 建構的 ES 模組) 更廣泛,自 80 版和 Safari 的最新版本起,Chrome 和 Edge 便一直提供支援。專屬工作站支援靜態和動態 ES 模組匯入作業。

第 83 版起,Chrome 和 Edge 便已在共用工作站中支援 ES 模組,但其他瀏覽器目前不提供支援。

不支援匯入地圖

匯入對應可讓執行階段環境重新編寫模組指定碼,例如在前方加上偏好的 CDN 網址,做為可載入 ES 模組的偏好 CDN。

雖然 Chrome 和 Edge 89 版以上支援匯入地圖,但目前無法與服務工作站搭配使用。

瀏覽器支援

91 版起,Chrome 和 Edge 均支援 Service Worker 中的 ES 模組。

Safari 已新增技術預覽 122 版的支援功能,開發人員應該日後就會在 Safari 的穩定版中看見這項功能。

程式碼範例

這是在網頁應用程式的 window 結構定義中使用共用 ES 模組,同時註冊使用相同 ES 模組的 Service Worker 的基本範例:

// Inside config.js:
export const cacheName = 'my-cache';
// Inside your web app:
<script type="module">
  import {cacheName} from './config.js';
  // Do something with cacheName.

  await navigator.serviceWorker.register('es-module-sw.js', {
    type: 'module',
  });
</script>
// Inside es-module-sw.js:
import {cacheName} from './config.js';

self.addEventListener('install', (event) => {
  event.waitUntil((async () => {
    const cache = await caches.open(cacheName);
    // ...
  })());
});

回溯相容性

如果所有瀏覽器都支援 Service Worker 中的 ES 模組,上述範例就能正常運作,不過截至本文撰寫時間為止,但並非如此。

為了配合沒有內建支援的瀏覽器,您可以透過 ES 模組與套件相容的套裝組合執行 Service Worker 指令碼,建立內含所有內嵌模組程式碼的 Service Worker,並可在舊版瀏覽器中運作。如果您嘗試匯入的模組已納入 IIFEUMD 格式,則可使用 importScripts() 匯入模組。

您擁有兩個版本的 Service Worker 後 (一個使用 ES 模組,另一個版本則不適用),您必須偵測目前瀏覽器支援的內容,並註冊對應的 Service Worker 指令碼。偵測支援的最佳做法目前是自由流通,但您可以按照這個 GitHub 問題中的討論取得相關建議。

_相片來源:Vlado PaunovicUnsplash 網站上