高级
Service workers
在 GitHub 上编辑此页面Service workers 充当代理服务器,处理应用内的网络请求。这使得你的应用可以在离线状态下运行,但即使你不需要离线支持(或由于你正在构建的应用类型而无法实际实现),通常也值得使用 service workers 通过预缓存已构建的 JS 和 CSS 来加快导航速度。
在 SvelteKit 中,如果你有一个 src/service-worker.js
文件(或 src/service-worker/index.js
),它将被捆绑并自动注册。如果需要,你可以更改 service worker 的位置。
如果你需要使用自己的逻辑注册 service worker 或使用其他解决方案,则可以 禁用自动注册。默认注册看起来像这样
ts
if ('serviceWorker' innavigator ) {addEventListener ('load', function () {navigator .serviceWorker .register ('./path/to/service-worker.js');});}
在 service worker 内永久链接
在 service worker 内,你可以访问 $service-worker
模块,它为你提供所有静态资产、构建文件和预渲染页面的路径。你还可以获得一个应用版本字符串,可用于创建唯一的缓存名称,以及部署的 base
路径。如果你的 Vite 配置指定了 define
(用于全局变量替换),它将应用于 service workers 以及你的服务器/客户端构建。
以下示例急切地缓存了构建的应用和 static
中的任何文件,并缓存所有其他请求,因为它们发生了。这将使每个页面在访问后离线运行。
ts
/// <reference types="@sveltejs/kit" />import {build ,files ,version } from '$service-worker';// Create a unique cache name for this deploymentconstCACHE = `cache-${version }`;constASSETS = [...build , // the app itself...files // everything in `static`];self .addEventListener ('install', (event ) => {// Create a new cache and add all files to itasync functionaddFilesToCache () {constProperty 'waitUntil' does not exist on type 'Event'.2339Property 'waitUntil' does not exist on type 'Event'.cache = awaitcaches .open (CACHE );awaitcache .addAll (ASSETS );}event .waitUntil (addFilesToCache ());});self .addEventListener ('activate', (event ) => {// Remove previous cached data from diskasync functiondeleteOldCaches () {for (constkey of awaitcaches .keys ()) {if (Property 'waitUntil' does not exist on type 'Event'.2339Property 'waitUntil' does not exist on type 'Event'.key !==CACHE ) awaitcaches .delete (key );}}event .waitUntil (deleteOldCaches ());});Property 'request' does not exist on type 'Event'.2339Property 'request' does not exist on type 'Event'.self .addEventListener ('fetch', (event ) => {// ignore POST requests etcProperty 'request' does not exist on type 'Event'.2339Property 'request' does not exist on type 'Event'.if (event .request .method !== 'GET') return;async functionrespond () {consturl = newURL (event .request .url );constcache = awaitcaches .open (CACHE );// `build`/`files` can always be served from the cacheif (ASSETS .includes (url .pathname )) {constresponse = awaitcache .match (url .pathname );if (response ) {returnresponse ;}}Property 'request' does not exist on type 'Event'.2339Property 'request' does not exist on type 'Event'.// for everything else, try the network first, but// fall back to the cache if we're offlinetry {constresponse = awaitfetch (event .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 respondWithif (!(response instanceofResponse )) {throw newProperty 'request' does not exist on type 'Event'.2339Property 'request' does not exist on type 'Event'.Error ('invalid response from fetch'); }if (response .status === 200) {cache .put (event .request ,response .clone ());}Property 'request' does not exist on type 'Event'.2339Property 'request' does not exist on type 'Event'.returnresponse ;} catch (err ) {constresponse = awaitcache .match (event .request );if (response ) {returnresponse ;}// if there's no cache, then just error out// as there is nothing we can do to respond to this requestthrowProperty 'respondWith' does not exist on type 'Event'.2339Property 'respondWith' does not exist on type 'Event'.err ;}}event .respondWith (respond ());});
缓存时要小心!在某些情况下,过时数据可能比离线时不可用的数据更糟糕。由于浏览器会在缓存过满时清空缓存,因此你还应小心缓存视频文件等大型资产。
在开发期间永久链接
服务工作者已打包用于生产,但未在开发期间打包。因此,只有支持 服务工作者中的模块 的浏览器才能在开发时使用它们。如果你手动注册你的服务工作者,则需要在开发中传递 { type: 'module' }
选项
ts
import {dev } from '$app/environment';navigator .serviceWorker .register ('/service-worker.js', {type :dev ? 'module' : 'classic'});
build
和prerendered
在开发期间是空数组
类型安全性永久链接
为服务工作者设置适当的类型需要一些手动设置。在你的 service-worker.js
中,将以下内容添加到文件顶部
ts
/// <reference types="@sveltejs/kit" />/// <reference no-default-lib="true"/>/// <reference lib="esnext" />/// <reference lib="webworker" />constsw = /** @type {ServiceWorkerGlobalScope} */ (/** @type {unknown} */ (self ));
ts
/// <reference types="@sveltejs/kit" />/// <reference no-default-lib="true"/>/// <reference lib="esnext" />/// <reference lib="webworker" />constsw =self as unknown asServiceWorkerGlobalScope ;
这会禁用对 DOM 类型(如 HTMLElement
)的访问,这些类型在服务工作者中不可用,并实例化正确的全局变量。将 self
重新分配给 sw
允许你在进程中对其进行类型转换(有几种方法可以做到这一点,但这是最简单的,不需要其他文件)。在文件的其余部分中使用 sw
而不是 self
。对 SvelteKit 类型的引用确保 $service-worker
导入具有正确的类型定义。如果你导入 $env/static/public
,则必须 // @ts-ignore
导入或将 /// <reference types="../.svelte-kit/ambient.d.ts" />
添加到引用类型。
其他解决方案永久链接
SvelteKit 的服务工作者实现故意是低级别的。如果你需要一个更成熟但更有主见的解决方案,我们建议查看 Vite PWA 插件 等解决方案,它使用 Workbox。有关服务工作者的更多一般信息,我们推荐 MDN 网络文档。