Skip to main content

Service workers

服务工作者充当代理服务器,处理您应用内的网络请求。这使得您的应用能够在离线状态下运行,即使您不需要离线支持(或者由于您正在构建的应用类型而无法实际实现),通常也值得使用服务工作者通过预缓存您的 JS 和 CSS 来加速导航。

在 SvelteKit 中,如果您有一个src/service-worker.js文件(或src/service-worker/index.js),它将被打包并自动注册。如果您需要,可以更改您的服务工作者位置

您可以根据需要禁用自动注册,如果您需要使用自己的逻辑或另一个解决方案来注册服务工作者。默认注册看起来可能像这样:

if ('serviceWorker' in var navigator: Navigatornavigator) {
	function addEventListener<"load">(type: "load", listener: (this: Window, ev: Event) => any, options?: boolean | AddEventListenerOptions): void (+1 overload)addEventListener('load', function () {
		var navigator: Navigatornavigator.Navigator.serviceWorker: ServiceWorkerContainer

Available only in secure contexts.

MDN Reference

serviceWorker
.ServiceWorkerContainer.register(scriptURL: string | URL, options?: RegistrationOptions): Promise<ServiceWorkerRegistration>register('./path/to/service-worker.js');
}); }

服务工作者内部

在服务工作者内部,您可以访问 $service-worker 模块,该模块为您提供了所有静态资源、构建文件和预渲染页面的路径。您还提供了一个应用程序版本字符串,您可以使用它来创建唯一的缓存名称,以及部署的 base 路径。如果您的 Vite 配置指定了 define(用于全局变量替换),这将应用于服务工作者以及您的服务器/客户端构建。

以下示例会预先缓存构建的应用程序以及static中的任何文件,并且会按发生顺序缓存所有其他请求。这样,一旦访问过每个页面,就可以离线工作。

/// <reference types="@sveltejs/kit" />
import { const build: string[]

An array of URL strings representing the files generated by Vite, suitable for caching with cache.addAll(build). During development, this is an empty array.

build
, const files: string[]

An array of URL strings representing the files in your static directory, or whatever directory is specified by config.kit.files.assets. You can customize which files are included from static directory using config.kit.serviceWorker.files

files
, const version: string

See config.kit.version. It’s useful for generating unique cache names inside your service worker, so that a later deployment of your app can invalidate old caches.

version
} from '$service-worker';
// Create a unique cache name for this deployment const const CACHE: stringCACHE = `cache-${const version: string

See config.kit.version. It’s useful for generating unique cache names inside your service worker, so that a later deployment of your app can invalidate old caches.

version
}`;
const const ASSETS: string[]ASSETS = [ ...const build: string[]

An array of URL strings representing the files generated by Vite, suitable for caching with cache.addAll(build). During development, this is an empty array.

build
, // the app itself
...const files: string[]

An array of URL strings representing the files in your static directory, or whatever directory is specified by config.kit.files.assets. You can customize which files are included from static directory using config.kit.serviceWorker.files

files
// everything in `static`
]; var self: Window & typeof globalThisself.function addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void (+1 overload)

Appends an event listener for events whose type attribute value is type. The callback argument sets the callback that will be invoked when the event is dispatched.

The options argument sets listener-specific options. For compatibility this can be a boolean, in which case the method behaves exactly as if the value was specified as options’s capture.

When set to true, options’s capture prevents callback from being invoked when the event’s eventPhase attribute value is BUBBLING_PHASE. When false (or not present), callback will not be invoked when event’s eventPhase attribute value is CAPTURING_PHASE. Either way, callback will be invoked if event’s eventPhase attribute value is AT_TARGET.

When set to true, options’s passive indicates that the callback will not cancel the event by invoking preventDefault(). This is used to enable performance optimizations described in § 2.8 Observing event listeners.

When set to true, options’s once indicates that the callback will only be invoked once after which the event listener will be removed.

If an AbortSignal is passed for options’s signal, then the event listener will be removed when signal is aborted.

The event listener is appended to target’s event listener list and is not appended if it has the same type, callback, and capture.

MDN Reference

addEventListener
('install', (event: Eventevent) => {
// Create a new cache and add all files to it async function function (local function) addFilesToCache(): Promise<void>addFilesToCache() { const const cache: Cachecache = await var caches: CacheStorage

Available only in secure contexts.

MDN Reference

caches
.CacheStorage.open(cacheName: string): Promise<Cache>open(const CACHE: stringCACHE);
await const cache: Cachecache.Cache.addAll(requests: Iterable<RequestInfo>): Promise<void> (+1 overload)addAll(const ASSETS: string[]ASSETS); } event: Eventevent.waitUntil(function (local function) addFilesToCache(): Promise<void>addFilesToCache()); }); var self: Window & typeof globalThisself.function addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void (+1 overload)

Appends an event listener for events whose type attribute value is type. The callback argument sets the callback that will be invoked when the event is dispatched.

The options argument sets listener-specific options. For compatibility this can be a boolean, in which case the method behaves exactly as if the value was specified as options’s capture.

When set to true, options’s capture prevents callback from being invoked when the event’s eventPhase attribute value is BUBBLING_PHASE. When false (or not present), callback will not be invoked when event’s eventPhase attribute value is CAPTURING_PHASE. Either way, callback will be invoked if event’s eventPhase attribute value is AT_TARGET.

When set to true, options’s passive indicates that the callback will not cancel the event by invoking preventDefault(). This is used to enable performance optimizations described in § 2.8 Observing event listeners.

When set to true, options’s once indicates that the callback will only be invoked once after which the event listener will be removed.

If an AbortSignal is passed for options’s signal, then the event listener will be removed when signal is aborted.

The event listener is appended to target’s event listener list and is not appended if it has the same type, callback, and capture.

MDN Reference

addEventListener
('activate', (event: Eventevent) => {
// Remove previous cached data from disk async function function (local function) deleteOldCaches(): Promise<void>deleteOldCaches() { for (const const key: stringkey of await var caches: CacheStorage

Available only in secure contexts.

MDN Reference

caches
.CacheStorage.keys(): Promise<string[]>keys()) {
if (const key: stringkey !== const CACHE: stringCACHE) await var caches: CacheStorage

Available only in secure contexts.

MDN Reference

caches
.CacheStorage.delete(cacheName: string): Promise<boolean>delete(const key: stringkey);
} } event: Eventevent.waitUntil(function (local function) deleteOldCaches(): Promise<void>deleteOldCaches()); }); var self: Window & typeof globalThisself.function addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void (+1 overload)

Appends an event listener for events whose type attribute value is type. The callback argument sets the callback that will be invoked when the event is dispatched.

The options argument sets listener-specific options. For compatibility this can be a boolean, in which case the method behaves exactly as if the value was specified as options’s capture.

When set to true, options’s capture prevents callback from being invoked when the event’s eventPhase attribute value is BUBBLING_PHASE. When false (or not present), callback will not be invoked when event’s eventPhase attribute value is CAPTURING_PHASE. Either way, callback will be invoked if event’s eventPhase attribute value is AT_TARGET.

When set to true, options’s passive indicates that the callback will not cancel the event by invoking preventDefault(). This is used to enable performance optimizations described in § 2.8 Observing event listeners.

When set to true, options’s once indicates that the callback will only be invoked once after which the event listener will be removed.

If an AbortSignal is passed for options’s signal, then the event listener will be removed when signal is aborted.

The event listener is appended to target’s event listener list and is not appended if it has the same type, callback, and capture.

MDN Reference

addEventListener
('fetch', (event: Eventevent) => {
// ignore POST requests etc if (event: Eventevent.request.method !== 'GET') return; async function function (local function) respond(): Promise<Response>respond() { const const url: URLurl = new var URL: new (url: string | URL, base?: string | URL) => URL

The URL interface represents an object providing static methods used for creating object URLs.

MDN Reference

URL class is a global reference for import { URL } from 'node:url' https://nodejs.org/api/url.html#the-whatwg-url-api

@sincev10.0.0
URL
(event: Eventevent.request.url);
const const cache: Cachecache = await var caches: CacheStorage

Available only in secure contexts.

MDN Reference

caches
.CacheStorage.open(cacheName: string): Promise<Cache>open(const CACHE: stringCACHE);
// `build`/`files` can always be served from the cache if (const ASSETS: string[]ASSETS.Array<string>.includes(searchElement: string, fromIndex?: number): boolean

Determines whether an array includes a certain element, returning true or false as appropriate.

@paramsearchElement The element to search for.
@paramfromIndex The position in this array at which to begin searching for searchElement.
includes
(const url: URLurl.URL.pathname: stringpathname)) {
const const response: Response | undefinedresponse = await const cache: Cachecache.Cache.match(request: RequestInfo | URL, options?: CacheQueryOptions): Promise<Response | undefined>match(const url: URLurl.URL.pathname: stringpathname); if (const response: Response | undefinedresponse) { return const response: Responseresponse; } } // for everything else, try the network first, but // fall back to the cache if we're offline try { const const response: Responseresponse = await function fetch(input: string | URL | globalThis.Request, init?: RequestInit): Promise<Response> (+1 overload)fetch(event: Eventevent.request); // if we're offline, fetch can return a value that is not a Response // instead of throwing - and we can't pass this non-Response to respondWith if (!(const response: Responseresponse instanceof
var Response: {
    new (body?: BodyInit | null, init?: ResponseInit): Response;
    prototype: Response;
    error(): Response;
    json(data: any, init?: ResponseInit): Response;
    redirect(url: string | URL, status?: number): Response;
}

This Fetch API interface represents the response to a request.

MDN Reference

Response
)) {
throw new
var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error
('invalid response from fetch');
} if (const response: Responseresponse.Response.status: numberstatus === 200) { const cache: Cachecache.Cache.put(request: RequestInfo | URL, response: Response): Promise<void>put(event: Eventevent.request, const response: Responseresponse.Response.clone(): Responseclone()); } return const response: Responseresponse; } catch (function (local var) err: unknownerr) { const const response: Response | undefinedresponse = await const cache: Cachecache.Cache.match(request: RequestInfo | URL, options?: CacheQueryOptions): Promise<Response | undefined>match(event: Eventevent.request); if (const response: Response | undefinedresponse) { return const response: Responseresponse; } // if there's no cache, then just error out // as there is nothing we can do to respond to this request throw function (local var) err: unknownerr; } } event: Eventevent.respondWith(function (local function) respond(): Promise<Response>respond()); });

[注意] 缓存时请小心!在某些情况下,过时的数据可能比离线时不可用的数据更糟。由于浏览器会在缓存太满时清空缓存,因此您还应注意缓存大型资产,如视频文件。

开发期间

服务工作者在生产环境中被打包,但在开发期间不会。因此,只有支持在服务工作者中使用模块的浏览器才能在开发时间使用它们。如果您手动注册服务工作者,您需要在开发时传递{ type: 'module' }选项:

import { const dev: boolean

Whether the dev server is running. This is not guaranteed to correspond to NODE_ENV or MODE.

dev
} from '$app/environment';
var navigator: Navigatornavigator.Navigator.serviceWorker: ServiceWorkerContainer

Available only in secure contexts.

MDN Reference

serviceWorker
.ServiceWorkerContainer.register(scriptURL: string | URL, options?: RegistrationOptions): Promise<ServiceWorkerRegistration>register('/service-worker.js', {
RegistrationOptions.type?: WorkerType | undefinedtype: const dev: boolean

Whether the dev server is running. This is not guaranteed to correspond to NODE_ENV or MODE.

dev
? 'module' : 'classic'
});

[!注意] buildprerendered 在开发期间为空数组

类型安全

设置服务工作者适当类型需要一些手动设置。在您的 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;

此操作禁用了对 DOM 类型定义的访问,例如HTMLElement,这些在服务工作者内部不可用,并实例化了正确的全局变量。将self重新赋值为sw允许你在过程中进行类型转换(有几种方法可以做到这一点,但这是最简单的一种,不需要额外的文件)。在文件的其他部分使用sw代替self。对 SvelteKit 类型的引用确保了$service-worker导入有正确的类型定义。如果你导入$env/static/public,你必须使用// @ts-ignore忽略导入或添加 /// <reference types="../.svelte-kit/ambient.d.ts" /> 到引用类型。

其他解决方案

SvelteKit 的服务工作者实现旨在易于使用,可能是大多数用户的良好解决方案。然而,在 SvelteKit 之外,许多 PWA 应用程序利用了Workbox库。如果您习惯使用 Workbox,您可能更喜欢Vite PWA 插件

参考文献

关于服务工作者更一般的信息,我们推荐MDN 网络文档

Edit this page on GitHub llms.txt