前言
Svelte,一個語法簡潔、入門容易,面向未來的前端框架。
從 Svelte 誕生之初,就備受開發者的喜愛,根據統計,從 2019 年到 2024 年,連續 6 年一直是開發者最感興趣的前端框架 No.1:
Svelte 以其獨特的編譯時優化機制著稱,具有輕量級、高性能、易上手等特性,非常適合構建輕量級 Web 項目。
為了幫助大家學習 Svelte,我同時搭建了 Svelte 最新的中文文檔站點。
如果需要進階學習,也可以入手我的小冊《Svelte 開發指南》,語法篇、實戰篇、原理篇三大篇章帶你係統掌握 Svelte!
歡迎圍觀我的“網頁版朋友圈”、加入“冴羽·成長陪伴社羣”,踏上“前端大佬成長之路”。
Service workers
Service workers 作為代理服務端,處理應用程序內部的網絡請求。這使得您的應用程序能夠離線工作,但即使您不需要離線支持(或由於您正在構建的應用程序類型而無法實現它),使用 service workers 預緩存構建的 JS 和 CSS 來加快導航速度,通常也是值得的。
在 SvelteKit 中,如果您有一個 src/service-worker.js 文件(或 src/service-worker/index.js),它將被打包並自動註冊。如果需要,您可以更改 service worker 的位置。
如果您需要使用自己的邏輯註冊 service worker 或使用其他解決方案,可以禁用自動註冊。默認註冊看起來類似這樣:
if ('serviceWorker' in navigator) {
addEventListener('load', function () {
navigator.serviceWorker.register('./path/to/service-worker.js');
});
}
Service Worker 內部
在 service worker 內部,您可以訪問 $service-worker 模塊,它為您提供所有靜態資源、構建文件和預渲染頁面的路徑。您還會獲得一個應用程序版本字符串,可用於創建唯一的緩存名稱,以及部署的 base 路徑。如果您的 Vite 配置指定了 define(用於全局變量替換),這也將應用於 service workers 以及服務端/客户端構建。
以下示例會盡可能早的緩存構建的應用程序和 static 中的所有文件,並在訪問時緩存所有其他請求。這將使每個頁面在訪問後都能離線工作。
// @errors: 2339
/// <reference types="@sveltejs/kit" />
import { build, files, version } from '$service-worker';
// 為此部署創建唯一的緩存名稱
const CACHE = `cache-${version}`;
const ASSETS = [
...build, // 應用程序本身
...files // `static` 中的所有內容
];
self.addEventListener('install', (event) => {
// 創建新緩存並添加所有文件
async function addFilesToCache() {
const cache = await caches.open(CACHE);
await cache.addAll(ASSETS);
}
event.waitUntil(addFilesToCache());
});
self.addEventListener('activate', (event) => {
// 從磁盤刪除以前的緩存數據
async function deleteOldCaches() {
for (const key of await caches.keys()) {
if (key !== CACHE) await caches.delete(key);
}
}
event.waitUntil(deleteOldCaches());
});
self.addEventListener('fetch', (event) => {
// 忽略 POST 請求等
if (event.request.method !== 'GET') return;
async function respond() {
const url = new URL(event.request.url);
const cache = await caches.open(CACHE);
// `build`/`files` 始終可以從緩存中提供服務
if (ASSETS.includes(url.pathname)) {
const response = await cache.match(url.pathname);
if (response) {
return response;
}
}
// 對於其他所有內容,首先嚐試網絡
// 但如果我們離線,則回退到緩存
try {
const response = await fetch(event.request);
// 如果我們離線,fetch 可能返回非 Response 值
// 而不是拋出錯誤 - 我們不能將這個非 Response 傳遞給 respondWith
if (!(response instanceof Response)) {
throw new Error('invalid response from fetch');
}
if (response.status === 200) {
cache.put(event.request, response.clone());
}
return response;
} catch (err) {
const response = await cache.match(event.request);
if (response) {
return response;
}
// 如果沒有緩存,就直接報錯
// 因為我們無法對這個請求做任何響應
throw err;
}
}
event.respondWith(respond());
});
[!NOTE] 緩存時要小心!在某些情況下,過時的數據可能比離線時無法獲取的數據更糟糕。由於瀏覽器會在緩存太滿時清空緩存,因此您還應該謹慎緩存大型資源,如視頻文件。
在開發過程中
service worker 在生產環境中會被打包,但在開發過程中不會。因此,只有支持 service workers 中的模塊 的瀏覽器才能在開發時使用它們。如果您手動註冊 service worker,在開發時需要傳遞 { type: 'module' } 選項:
import { dev } from '$app/environment';
navigator.serviceWorker.register('/service-worker.js', {
type: dev ? 'module' : 'classic'
});
[!NOTE] 在開發環境中,build和prerendered是空數組
類型安全
為 service workers 設置適當的類型需要一些手動設置。在您的 service-worker.js 中,在文件頂部添加以下內容:
/// <reference types="@sveltejs/kit" />
/// <reference no-default-lib="true"/>
/// <reference lib="esnext" />
/// <reference lib="webworker" />
const sw = /** @type {ServiceWorkerGlobalScope} */ (/** @type {unknown} */ (self));
/// <reference types="@sveltejs/kit" />
/// <reference no-default-lib="true"/>
/// <reference lib="esnext" />
/// <reference lib="webworker" />
const sw = self as unknown as ServiceWorkerGlobalScope;
這會禁用對 service worker 中不可用的 DOM 類型(如 HTMLElement)的訪問,並實例化正確的全局變量。將 self 重新賦值給 sw 允許您在此過程中進行類型轉換(有幾種方法可以做到這一點,但這是最簡單的,不需要額外的文件)。在文件的其餘部分使用 sw 而不是 self。
對 SvelteKit 類型的引用確保 $service-worker 導入具有適當的類型定義。如果您導入 $env/static/public,您要麼必須使用 // @ts-ignore 註釋導入,要麼添加 /// <reference types="../.svelte-kit/ambient.d.ts" /> 到引用類型中。
其他解決方案
SvelteKit 的 service worker 實現故意保持低級別。如果您需要更全功能但也更有主見的解決方案,我們建議查看像 Vite PWA 插件 這樣的解決方案,它使用 Workbox。有關 service workers 的更多一般信息,我們推薦 MDN web 文檔。
Svelte 中文文檔
點擊查看中文文檔:SvelteKit Service workers
系統學習 Svelte,歡迎入手小冊《Svelte 開發指南》。語法篇、實戰篇、原理篇三大篇章帶你係統掌握 Svelte!
此外我還寫過 JavaScript 系列、TypeScript 系列、React 系列、Next.js 系列、冴羽答讀者問等 14 個系列文章, 全系列文章目錄:https://github.com/mqyqingfeng/Blog
歡迎圍觀我的“網頁版朋友圈”、加入“冴羽·成長陪伴社羣”,踏上“前端大佬成長之路”。