{T}

Nuxt3 PWA 配置问题排查与修复实践

概述

Nuxt3 通过 @vite-pwa/nuxt 模块集成 PWA 能力,但实际配置中常遇到 Service Worker 未注册、缓存不完整、更新不生效等问题。本文记录完整的排查清单与 Workbox 缓存优化方案。

学习目标

  • 掌握 PWA 注册状态的验证方法
  • 学会排查 Service Worker 未注册的常见原因
  • 掌握 Workbox globPatterns 缓存类型配置
  • 理解 periodicSyncForUpdates 后台更新机制

一、PWA 状态验证

1.1 验证步骤

  1. 打开 DevTools → Application 面板
  2. Service Workers:确认 sw.js 状态为 activated
  3. Cache Storage:确认存在缓存条目
  4. Manifest:确认 manifest.webmanifest 正确加载

1.2 常见问题速查

问题原因解决方案
SW 未注册缺少 VitePwaManifest 组件app.vue 中添加组件
缓存文件不全globPatterns 未覆盖文件类型扩展缓存类型列表
SW activated 始终 false更新周期未配置设置 periodicSyncForUpdates
离线无法访问缓存范围太小扩大 globPatterns

二、基础配置

2.1 安装模块

bash
pnpm add -D @vite-pwa/nuxt
typescript
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@vite-pwa/nuxt'],
  pwa: {
    registerType: 'autoUpdate',
    manifest: {
      name: 'My Nuxt PWA',
      short_name: 'NuxtPWA',
      theme_color: '#ffffff',
      icons: [
        { src: '/pwa-192x192.png', sizes: '192x192', type: 'image/png' },
        { src: '/pwa-512x512.png', sizes: '512x512', type: 'image/png' },
      ],
    },
  },
})

2.2 根组件配置

Vue SFC
<!-- app.vue -->
<template>
  <div>
    <NuxtPage />
    <!-- 必须:注入 PWA manifest 链接 -->
    <VitePwaManifest />
  </div>
</template>

缺少 <VitePwaManifest /> 是 SW 未注册的最常见原因。


三、Workbox 缓存优化

3.1 扩展缓存文件类型

默认 globPatterns 只缓存 js/css/html,图片和字体会缺失:

typescript
// nuxt.config.ts
export default defineNuxtConfig({
  pwa: {
    workbox: {
      globPatterns: [
        // 核心资源
        '**/*.{js,css,html}',
        // 图片资源
        '**/*.{png,jpg,jpeg,svg,gif,webp,ico,avif}',
        // 字体资源
        '**/*.{woff,woff2,ttf,eot,otf}',
        // 数据资源
        '**/*.{json,xml}',
      ],
    },
  },
})

3.2 缓存全部文件(小型项目)

typescript
pwa: {
  workbox: {
    globPatterns: ['**/*.*'],
  },
}
风险说明
大文件缓存视频/音频文件撑爆缓存配额
安装缓慢首次缓存大量文件耗时长
配额超限浏览器存储配额有限(通常 50MB-2GB)

大型项目应精确配置类型,排除大体积资源。

3.3 运行时缓存策略

typescript
pwa: {
  workbox: {
    runtimeCaching: [
      {
        urlPattern: /^https:\/\/api\.example\.com\/.*/i,
        handler: 'NetworkFirst',
        options: {
          cacheName: 'api-cache',
          expiration: { maxEntries: 50, maxAgeSeconds: 300 },
        },
      },
      {
        urlPattern: /\.(?:png|jpg|jpeg|svg|gif|webp)$/,
        handler: 'CacheFirst',
        options: {
          cacheName: 'image-cache',
          expiration: { maxEntries: 100, maxAgeSeconds: 60 * 60 * 24 * 30 },
        },
      },
    ],
  },
}

四、后台更新配置

4.1 periodicSyncForUpdates

typescript
pwa: {
  devOptions: {
    enabled: true,   // 开发环境也启用 SW(调试用)
  },
  workbox: {
    // 每 60 秒检查一次 SW 更新
    periodicSyncForUpdates: 60,
  },
}

不配置此项时,SW 更新检查依赖浏览器默认策略(通常 24 小时),导致新版本长时间不生效。

4.2 更新流程

图表渲染中…

registerType: 'autoUpdate' 配合 periodicSyncForUpdates 实现静默更新。


五、排查清单

遇到问题时按顺序检查:

  1. app.vue 是否包含 <VitePwaManifest />
  2. nuxt.config.ts 中 pwa 模块是否正确注册
  3. DevTools → Application → Service Workers 状态
  4. Cache Storage 中的缓存条目是否覆盖关键资源
  5. globPatterns 是否包含项目使用的文件类型
  6. 是否配置了 periodicSyncForUpdates
  7. 构建产物(.output/public)中是否存在 sw.js

常见问题

Q: 开发环境需要启用 PWA 吗?

默认不启用(避免 SW 缓存干扰 HMR)。调试 PWA 时设置 devOptions.enabled: true,注意开发环境的 SW 可能缓存旧资源,需手动 Unregister 后刷新。

Q: iOS Safari 对 PWA 支持如何?

iOS 16.4+ 支持 Web Push,但后台同步(Background Sync)支持有限。iOS 上 PWA 需通过"添加到主屏幕"安装,缓存策略受 ITP 影响可能更激进地清理。

Q: 如何强制用户更新到新版本?

registerType: 'prompt' 模式下可监听更新事件,弹出提示让用户手动刷新:

typescript
// plugins/pwa-update.client.ts
export default defineNuxtPlugin(() => {
  const pwa = useRegisterSW()
  // 监听新 SW 就绪,提示用户刷新
})

延伸阅读