ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

SvelteKit `$service-worker` 模块全解:从 SvelteKit 2 遗留导出到 `$app/manifest` 迁移指南

2026/9/21 15:12:45 拓冰建站 浏览量
SvelteKit `$service-worker` 模块全解:从 SvelteKit 2 遗留导出到 `$app/manifest` 迁移指南 Web框架后端前端【免费下载链接】kitweb development, streamlined项目地址https://gitcode.com/gh_mirrors/kit/kit点击查看免费下载本指南以仓库文档 documentation/docs/99-legacy-reference/10-$service-worker.md 为核心系统梳理 SvelteKit 2 中$service-worker模块的 5 个导出base、build、files、prerendered、version及其在新版本中的替代方案。读者将掌握该遗留模块的每个 API 语义、为什么被移除、如何用$app/manifest、$app/env、$app/paths完成等价改写以及如何借助仓库源码理解底层实现。一、背景$service-worker是什么为什么被移除$service-worker是 SvelteKit 2 时代为 Service Worker服务工作线程场景专门提供的虚拟模块。SvelteKit 约定只要项目中存在src/service-worker/index.ts或.js该文件就会被打包并在生产环境自动注册。在 Service Worker 内部开发者通常需要知道「哪些文件是可缓存资源」「应用部署版本号是什么」「站点的 base path 是多少」——$service-worker模块就是为此提供这些元数据的入口。SvelteKit 3 之后该模块被彻底移除其能力被拆分到三个通用模块中$app/manifest提供immutable、assets、prerendered三个数组取代build与files$app/env提供version取代$service-worker的version$app/paths提供resolve(...)以及asset(...)取代base。仓库的迁移指南 documentation/docs/60-appendix/35-migrating-to-sveltekit-3.md 中专门设有一节$service-worker(removed)明确说明Import version from $app/env, assets, immutable and prerendered from $app/manifest, and resolved from $app/paths instead.在源码层面Vite 插件在 packages/kit/src/exports/vite/index.js 中维护了一个removed_modules数组通过pattern: /^\$service-worker(?:\?.*)?$/拦截对$service-worker的导入并输出一条明确的移除提示$service-worker has been removed. Use immutable, assets and prerendered from $app/manifest, version from $app/env, and resolve(...) from $app/paths instead.这意味着即便在升级后的代码中误写了import { files } from $service-worker构建/开发时也会得到清晰可读的迁移指引而不是含糊的模块找不到错误。二、$service-worker的 5 个导出与逐一替换方案原文档定义了该模块的全部导出以下逐一说明其语义与替代 API。替换时遵循一条主线凡是描述「应用构建产物/静态资源/预渲染页面」的数据都来自$app/manifest凡是描述「部署版本」的都来自$app/env凡是描述「路径前缀」的都来自$app/paths。1.base表示应用 base path 的根相对路径。请改用$app/paths中的resolve(...)。在 SvelteKit 2 中base对应配置中的paths.base即应用部署在域名子目录时所需的路径前缀。Service Worker 需要它来拼接出资源的绝对 pathname。替代方式$app/paths导出的resolve(...)可以将一个路径解析为带 base 前缀的完整 pathname其实现位于 packages/kit/src/runtime/app/paths/client.jsimport { resolve } from $app/paths; // 返回 base /blog/hello-world例如 /my-app/blog/hello-world const url resolve(/blog/[slug], { slug: hello-world });resolve的两种用法传入一个普通路径字符串如blog/hello-world结果会自动加上 base 前缀传入一个路由 ID如/blog/[slug]与参数对象会先填充动态段再拼接 base。若只需要静态资源 URL还可以使用同模块的asset(...)服务端实现见 packages/kit/src/runtime/app/paths/server.js它会以assets配置为前缀解析文件路径。2.buildstring[]类型的数组包含 Vite 生成的文件即打包产物。开发环境下为空。请改用$app/manifest中的immutable。build在 SvelteKit 2 中列出的是构建输出_app/immutable/...这类带内容哈希、可长期缓存的文件用于在install事件中预缓存从而让应用离线可用或加速导航。替代方式$app/manifest导出immutable——Vite 输出的不可变构建文件列表。两者的对应关系可从清单生成源码得到印证packages/kit/src/core/sync/write_app_manifest.js 中写明了export const immutable ...构建期以占位符形式输出由replace_manifest_placeholder_variables在构建完成后回填真实值开发期则为空数组。一个关键差异$app/manifest中的条目是对象而不是字符串每个条目至少包含path字段。以immutable为例条目形如{ path: /_app/immutable/entry/start.a1b2c3.js }。因此迁移时需要对数组做一次映射// 旧写法SvelteKit 2 import { build } from $service-worker; const CACHEABLE build; // 新写法SvelteKit 3 import { immutable } from $app/manifest; import { resolve } from $app/paths; const CACHEABLE immutable.map((asset) resolve(asset.path));注意immutable/assets中的路径是相对于 base path 的所以先用resolve(...)解析为绝对 pathname才能与fetch事件中url.pathname正确匹配。3.filesstring[]类型的数组包含static目录中的文件。请改用$app/manifest中的assets。files对应static/目录下未经构建处理的静态资源图片、favicon、robots.txt 等。替代方式$app/manifest导出assets。同样地条目为对象需要映射出pathimport { assets } from $app/manifest; import { resolve } from $app/paths; const STATIC_FILES assets.map((asset) resolve(asset.path));write_app_manifest.js中stringify_assets的实现表明assets在开发期就会填充来自 manifest data 的asset.file而immutable/prerendered在开发期为[]——这一点与原文档对build/prerendered「开发期为空」的描述完全一致。4.prerenderedstring[]类型的数组包含预渲染的页面。开发期间为空。请改用$app/manifest中的prerendered。当应用开启prerender如使用adapter-static构建纯静态站时prerendered列出所有已预渲染的 HTML 页面路径Service Worker 可据此在离线时提供这些页面。替代方式$app/manifest导出同名prerendered用法与前两者一致对象数组、需resolve。仓库的静态适配器测试应用 packages/adapter-static/test/apps/prerendered 正是使用预渲染页面的典型场景。5.versionconfig.version.name的值用于填充缓存名。请改用$app/env中的version。version用于生成「按部署隔离」的缓存名每次发布都会得到一个新的版本号Service Worker 用它构建唯一的 cache 名称并在activate阶段清理旧缓存从而避免新旧部署资源互相污染。替代方式$app/env导出version。其实现位于 packages/kit/src/runtime/app/env/client.js注释明确写着「The value ofconfig.version.name」服务端版本则来自__SVELTEKIT_APP_VERSION__见 packages/kit/src/runtime/app/env/server.js。用法不变import { version } from $app/env; const CACHE cache-${version};顺带说明与旧的$app/environment相比$app/env的一个优势是可以在 Service Worker 中直接导入迁移指南 documentation/docs/60-appendix/35-migrating-to-sveltekit-3.md 对此有专门说明这正是它适合取代$service-worker.version的原因。三、迁移实操用新模块重写一个完整的 Service Worker仓库的官方指南 documentation/docs/30-advanced/40-service-workers.md 给出了一个可直接落地的完整示例它使用的全部是$service-worker的替代模块可以作为迁移后的目标形态/// file: src/service-worker.js import { self } from $app/service-worker; import { version } from $app/env; import { immutable, assets } from $app/manifest; import { resolve } from $app/paths; // 为该部署创建唯一的缓存名 const CACHE cache-${version}; // immutable/assets 中的路径相对于 base path // 用 resolve(...) 解析为可与 url.pathname 匹配的绝对 pathname const ASSETS [ ...immutable.map((asset) resolve(asset.path)), // Vite 构建产物 ...assets.map((asset) resolve(asset.path)) // 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 等非 GET 请求 if (event.request.method ! GET) return; async function respond() { const url new URL(event.request.url); const cache await caches.open(CACHE); // immutable/assets 永远可以从缓存直接命中 if (ASSETS.includes(url.pathname)) { const response await cache.match(url.pathname); if (response) return response; } // 其余请求优先走网络 try { const response await fetch(event.request); if (response.status 200 !response.headers.get(cache-control)?.includes(no-store)) { // 在后台把响应写入缓存供下次使用 void cache.put(event.request, response.clone()); } return response; } catch (error) { // 网络失败时回退到已缓存数据 const response await cache.match(event.request); if (response) return response; throw error; } } event.respondWith(respond()); });对照前文可以清楚看到迁移映射关系$service-worker已移除迁移目标说明base$app/paths的resolve(...)/asset(...)拼接 base 前缀build$app/manifest的immutableVite 构建产物开发期为[]files$app/manifest的assetsstatic目录文件prerendered$app/manifest的prerendered预渲染页面开发期为[]version$app/env的version即config.version.name四、类型安全与项目结构要求$service-worker的移除不改变 SvelteKit 对 Service Worker 的类型约定。Service Worker 运行在与应用主体不同的上下文Worker 全局作用域需要独立类型配置项目根tsconfig.json必须排除 Service Worker 代码/// file: tsconfig.json { extends: $app/tsconfig, include: [src, test], exclude: [src/service-worker] }src/service-worker/目录下放置独立的tsconfig.json继承 Service Worker 专用类型/// file: src/service-worker/tsconfig.json { extends: $app/tsconfig/service-worker }这样$app/service-worker导出的self才会被正确类型化为ServiceWorkerGlobalScopefetch事件处理器拥有完整的类型提示。五、自动注册、手动注册与版本更新机制$service-worker模块的移除不影响 SvelteKit 对 Service Worker 的注册与管理机制但这部分机制与「在缓存中正确使用 version」密切相关自动注册生产环境 SvelteKit 会在服务端渲染的 HTML 中注入类似navigator.serviceWorker.register(./service-worker.js, { type: module })的脚本可用配置项serviceWorker关闭自动注册改为自行调用register。开发期差异Service Worker 仅在生产环境打包开发期间不会执行捆绑因此依赖构建产物的缓存逻辑immutable在开发期天然为空——这与原文档「build/prerendered开发期为空」的描述互相印证。版本轮询version被用于创建部署隔离的缓存名同时config.version的轮询机制x-sveltekit-version响应头 version.json会在检测到新部署时触发 Service Worker 更新然后回退到整页导航。仓库中$app/env的version与$app/state的版本检测逻辑见 packages/kit/src/runtime/app/state/client.svelte.js共同支撑这一行为。六、迁移时易踩的坑对象数组 vs 字符串数组$app/manifest的immutable、assets、prerendered是{ path }对象数组不能直接当作字符串数组用于cache.addAll必须先map出path并用resolve解析。路径需要解析为绝对 pathnamefetch事件中url.pathname是绝对路径而 manifest 中的路径是相对于 base path 的漏掉resolve(...)会导致缓存匹配失败。prerendered/immutable开发期为空迁移代码不要在开发期断言它们非空调试缓存逻辑应以生产构建为准。清理旧缓存依赖version如果直接硬编码缓存名而不使用version旧部署的缓存将永远不会被清理可能积累大量过期资源。七、相关文档与源码索引本文主体documentation/docs/99-legacy-reference/10-$service-worker.mdService Worker 完整指南含类型安全、手动注册、更新策略documentation/docs/30-advanced/40-service-workers.mdSvelteKit 3 迁移指南含$service-workerremoved 章节documentation/docs/60-appendix/35-migrating-to-sveltekit-3.md新模块参考文档$app/manifest、$app/env、$app/paths移除提示实现packages/kit/src/exports/vite/index.js$app/manifest清单生成实现packages/kit/src/core/sync/write_app_manifest.jsversion实现packages/kit/src/runtime/app/env/client.js、packages/kit/src/runtime/app/env/server.jsresolve实现packages/kit/src/runtime/app/paths/client.js结论$service-worker模块的 5 个导出在 SvelteKit 3 中均有明确对等的替代 API。迁移的本质是一次「数据来源」的重定向——资源清单交给$app/manifest版本号交给$app/env路径解析交给$app/paths。按照本文的映射表与示例逐项替换即可在不改变缓存策略的前提下完成平滑升级同时享受新模块「可在 Service Worker 中直接导入、类型更完善、数据更结构化」的优势。赞分享Web框架后端前端【免费下载链接】kitweb development, streamlined项目地址https://gitcode.com/gh_mirrors/kit/kit点击查看免费下载相关推荐SvelteKit 中的 Service Worker 深度指南SvelteKit 中的 Service Worker 深度指南 什么是 Service Worker Service Worker 是现代 Web 开发中一项Web框架后端前端mcp-servers之Puppeteer服务器AI驱动浏览器自动化与网页抓取的完整实战教程mcp servers之Puppeteer服务器AI驱动浏览器自动化与网页抓取的完整实战教程 想让 AI 自动打开网页、填写表单、点击按钮、截图取证在开源项Web框架后端前端SvelteKit Cloudflare 适配器迁移指南移除 platform、改用 cloudflare:workers 模块SvelteKit Cloudflare 适配器迁移指南移除 platform、改用 cloudflare:workers 模块 本文基于 SvelteKitWeb框架后端前端上一篇解锁200Claude技能模块的隐藏用法让AI助手成为你的全能工作伙伴下一篇如何用 docsify-to-pdf 把 IoT-For-Beginners 课程目录导出为本地 PDF创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考