Skip to content

常见问题解答

IDE 错误 'Cannot find module' (ts2307)

如果你的 TypeScript 构建时或 IDE 抱怨在导入时找不到模块或类型定义,请将以下内容添加到tsconfig.jsoncompilerOptions.types 数组中:

json
{
  "compilerOptions": {
    "types": ["vite-plugin-pwa/client"]
  }
}

或者你可以添加以下引用到任何 d.ts 文件中(例如,在 vite-env.d.tsglobal.d.ts 中):

ts
/// <reference types="vite-plugin-pwa/client" />

类型声明

您可以在以下types.ts module中找到 vite-plugin-pwa 插件配置选项的完整列表。

你可以在下面的client.d.ts中找到所有 vite-plugin-pwa 虚拟模块声明。

Web 应用清单和 401 状态码(未授权)

浏览器发送的 web 清单请求没有凭据,如果你的网站在认证后 ,请求将失败,返回一个 401 Unauthorized error —— 即使用户已经登录了

要发送带有凭据的请求, <link rel="manifest"> 需要 crossorigin="use-credentials" 属性,你可以通过插件选项中的 useCredentials 来启用该属性:

ts
useCredentials: true;

Service Worker errors on browser

查看新的 Vite 构建部分获取更多详细信息,以下描述的错误已在 v0.18.0+ 中修复,并且不需要使用 iife 格式来构建您的 service worker。

如果您的 service worker 代码使用意外的 exports 编译(例如: export default require_sw(); ),您可以将构建输出格式更改为 iife ,将以下代码添加到您的 pwa 配置:

ts
injectManifest: {
  rollupFormat: 'iife';
}

Error: Unable to find a place to inject the manifest

如果你没有 precaching (self.__WB_MANIFEST)来自定义 service worker,并且在构建过程中出现此错误,你需要在 pwa 插件配置中禁用 injection point (仅从版本 ^0.14.0 中可用):

ts
injectManifest: {
  injectionPoint: undefined;
}

Service Worker Registration Errors

如果你想通知用户处理 Service Worker 注册错误,可以在 main.tsmain.js 中使用以下代码:

ts
import { registerSW } from 'virtual:pwa-register';

const updateSW = registerSW({
  onRegisterError(error) {},
});

然后在 onRegisterError 内部,只需通知用户注册 service worker 时出现了错误。

Missing assets from SW precache manifest

提示

从版本 0.20.2 开始,如果在构建服务工人时出现 maximumFileSizeToCacheInBytes 警告,该插件将抛出错误。

如果你发现 service worker 的预缓存清单中缺少任何资产,你应该检查一下它们是否超过了 maximumFileSizeToCacheInBytes ,默认值为 2 MiB

你可以根据自己的需要增加这个值,例如将资产限制在 3MiB 以内

  • 在使用 generateSW 策略时:
ts
workbox: {
  maximumFileSizeToCacheInBytes: 3000000;
}
  • 在使用 injectManifest 策略时:
ts
injectManifest: {
  maximumFileSizeToCacheInBytes: 3000000;
}

排除路由

如果你需要将某些路由排除在 service worker 拦截之外:

如果你在构建应用程序时遇到了 navigator is undefinedwindow is undefined 错误,那么你的应用程序是在 SSR / SSG 环境下配置的

这种错误可能是由于使用了不支持SSR/SSG的插件或库导致的:您的代码将在客户端和构建过程中的服务器端被调用,因此在构建应用程序时,服务器端的逻辑将被调用,但是在服务器端没有navigator/window,所以它是undefined

第三方库

如果错误的原因是第三方库不知道 SSR / SSG 环境,解决错误的方法是在定义 window 时使用动态导入来导入它:

ts
if (typeof window !== 'undefined') import('./library-not-ssr-ssg-aware');

或者,如果你的框架支持组件 onMount / onMounted 生命周期钩子,你可以在回调中导入第三方库,因为框架应该只在客户端调用这个生命周期钩子,你应该检查你的框架文档

Vite PWA Virtual Module

如果错误是由此插件的虚拟模块引起的,您可以按照 SSR/SSG: Prompt for update SSR/SSG: Automatic reload方式来解决此问题。

如果您使用的是 autoUpdate 策略和支持 isReadyrouter(即路由器允许在当前组件路由完成加载时注册一个回调),您可以延迟 service worker 注册到路由器回调上。

例如,使用 vue-router,您可以使用以下代码为 autoUpdate 策略注册 service worker

ts
import type { Router } from 'vue-router';

export function registerPWA(router: Router) {
  router.isReady().then(async () => {
    const { registerSW } = await import('virtual:pwa-register');
    registerSW({ immediate: true });
  });
}

Vitesse Template 中可以看到一个SSR / SSG 环境(vite-ssg)的autoUpdate策略示例。

如果你正在使用prompt策略,你将需要使用异步的方式来动态导入来加载 ReloadPrompt 组件,例如,使用 vue 3:

vue
// src/App.vue
<script setup lang="ts">
import { defineAsyncComponent } from 'vue';

const ClientReloadPrompt =
  typeof window !== 'undefined'
    ? defineAsyncComponent(() => import('./ReloadPrompt.vue'))
    : null;
</script>

<template>
  <router-view />
  <template v-if="ClientReloadPrompt">
    <ClientReloadPrompt />
  </template>
</template>

或者使用 svelte:

html
<!-- App.svelte -->
<script>
  import { onMount } from 'svelte';
  let ClientReloadPrompt;
  onMount(async () => {
    typeof window !== 'undefined' && (ClientReloadPrompt = await import('$lib/ReloadPrompt.svelte')).default)
  })
</script>
... {#if ClientReloadPrompt}
<svelte:component this="{ClientReloadPrompt}" />
{/if}

您可以检查 SSR / SSG 环境,看看它是否提供了一些仅在客户端注册组件的方法。接下来是 Vitesse Template上的 vite-ssg,它提供了 ClientOnly 功能组件,这将防止在服务器端注册组件,所以你可以使用原始代码,包含 ReloadPrompt 组件:

vue
// src/App.vue
<template>
  ...
  <ClientOnly>
    <ReloadPrompt />
  </ClientOnly>
</template>

VitePress

你可以查看这个网站的 ReloadPrompt 组件来调用 PWA 虚拟模块:

vue
<script setup lang="ts">
import { onBeforeMount, ref } from 'vue';

const needRefresh = ref(false);

let updateServiceWorker: (() => Promise<void>) | undefined;

function onNeedRefresh() {
  needRefresh.value = true;
}
async function close() {
  needRefresh.value = false;
}

onBeforeMount(async () => {
  const { registerSW } = await import('virtual:pwa-register');
  updateServiceWorker = registerSW({
    immediate: true,
    onNeedRefresh,
  });
});
</script>

多项目和框架的 Monorepo

从版本 0.14.5 开始, vite-plugin-pwa 为每个框架提供了类型,因此您可以在单个代码库项目中导入适当的虚拟模块。不要通过 vite-plugin-pwa/client(tsconfig.json 文件或 TypeScript 引用)使用 client.d.ts,而是使用以下任意一个虚拟模块

  • virtual:pwa-register/react: 配置 vite-plugin-pwa/react.
  • virtual:pwa-register/preact: 配置 vite-plugin-pwa/preact.
  • virtual:pwa-register/solid: 配置 vite-plugin-pwa/solid.
  • virtual:pwa-register/svelte: 配置 vite-plugin-pwa/svelte.
  • virtual:pwa-register/vanillajs: 配置 vite-plugin-pwa/vanillajs.
  • virtual:pwa-register/vue: 配置 vite-plugin-pwa/vue.

vite-plugin-pwa repo 的示例文件夹中,您可以找到 preactsolidsvelte 的一些示例。

在开发环境中屏蔽 workbox-build 警告

如果您正在使用vite-plugin-pwagenerateSW 策略, 在开发环境中你可以使用suppressWarnings选项来屏蔽workbox-build 的警告:

ts
devOptions: {
  suppressWarnings: true;
}

启用此选项, vite-plugin-pwa 开发插件将:

  • dev-dist 文件夹中生成一个空的 suppress-warnings.js 文件。
  • 修改 workbox.globPatterns 选项为 [*.js']

在MIT许可下发布.