You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Serwist离线功能24小时后失效,需自定义持久化时长

问题解决:Next.js 15 + Serwist 离线时效与网络慢加载优化

问题1:离线功能仅生效24小时

原因分析

默认defaultCache中静态资源和导航请求的缓存策略未配置持久化过期规则,且你排除了/_next/(.*)路径,导致Next.js核心静态资源(JS/CSS/页面)未进入预缓存池,依赖浏览器临时缓存,24小时后易被自动清理。

修复方案

  1. 为静态资源添加带过期规则的持久化缓存策略
  2. 自定义导航请求缓存规则,延长缓存有效期

修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 16:12:29