Serwist离线功能24小时后失效,需自定义持久化时长
问题解决:Next.js 15 + Serwist 离线时效与网络慢加载优化
问题1:离线功能仅生效24小时
原因分析
默认defaultCache中静态资源和导航请求的缓存策略未配置持久化过期规则,且你排除了/_next/(.*)路径,导致Next.js核心静态资源(JS/CSS/页面)未进入预缓存池,依赖浏览器临时缓存,24小时后易被自动清理。
修复方案
- 为静态资源添加带过期规则的持久化缓存策略
- 自定义导航请求缓存规则,延长缓存有效期
修改sw.ts配置(需先安装@serwist/expiration依赖):
import { defaultCache } from "@serwist/next/worker"; import type { PrecacheEntry, SerwistGlobalConfig } from "serwist"; import { CacheFirst, NetworkFirst, NetworkOnly, Serwist } from "serwist"; import { ExpirationPlugin } from "@serwist/expiration"; declare global { interface WorkerGlobalScope extends SerwistGlobalConfig { __SW_MANIFEST: (PrecacheEntry | string)[] | undefined; } } declare const self: ServiceWorkerGlobalScope; const serwist = new Serwist({ precacheEntries: self.__SW_MANIFEST, skipWaiting: true, clientsClaim: true, navigationPreload: true, runtimeCaching: [ { matcher: ({ url }) => url.pathname.endsWith('/logo.png') || url.pathname.endsWith('/logo-144.png'), handler: new CacheFirst({ cacheName: "static-images", plugins: [ new ExpirationPlugin({ maxAgeSeconds: 30 * 24 * 60 * 60, // 缓存30天 purgeOnQuotaError: true, // 浏览器缓存配额不足时自动清理旧资源 }), ], }), }, // 为Next.js静态资源添加持久化缓存 { matcher: ({ url }) => url.pathname.startsWith("/_next/static/"), handler: new CacheFirst({ cacheName: "next-static-assets", plugins: [ new ExpirationPlugin({ maxAgeSeconds: 30 * 24 * 60 * 60, purgeOnQuotaError: true, }), ], }), }, // 自定义导航请求缓存规则 { matcher: ({ request }) => request.mode === "navigate" && !request.url.includes("/admin"), handler: new NetworkFirst({ cacheName: "navigation-routes", plugins: [ new ExpirationPlugin({ maxAgeSeconds: 7 * 24 * 60 * 60, // 缓存7天 maxEntries: 50, // 最多缓存50个页面路由 }), ], }), }, { matcher: ({ url }) => url.pathname === "/api", handler: new NetworkOnly(), }, // 过滤defaultCache中已自定义的规则,避免冲突 ...defaultCache.filter(entry => { const matcher = entry.matcher as any; return !(typeof matcher === "function" && ( matcher({ url: new URL("https://example.com/_next/static/test") }) || matcher({ request: { mode: "navigate", url: "https://example.com/" } }) )); }), ], }); serwist.addEventListeners();
安装依赖:
npm install @serwist/expiration
问题2:网络缓慢时不优先加载缓存
原因分析
默认导航策略未设置网络超时阈值,navigationPreload开启后会等待网络响应,未快速 fallback 到缓存内容。
修复方案
为导航请求的NetworkFirst策略添加networkTimeoutSeconds配置,超时后直接返回缓存,后台异步更新缓存。
修改上述sw.ts中导航请求的handler:
handler: new NetworkFirst({ cacheName: "navigation-routes", networkTimeoutSeconds: 3, // 3秒超时后立即返回缓存 plugins: [ new ExpirationPlugin({ maxAgeSeconds: 7 * 24 * 60 * 60, maxEntries: 50, }), ], }),
额外优化建议
- 若需核心页面长期离线可用,可调整
next.config.js的exclude规则,移除/_next/(.*)(保留/api/(.*)和/admin的排除),让静态资源进入预缓存池 - 定期清理旧缓存:依赖
ExpirationPlugin的自动清理规则,避免缓存膨胀占用浏览器空间
内容的提问来源于stack exchange,提问作者Ahmed Abid
相关产品推荐
相关产品推荐

