常见问题解答
IDE 错误 'Cannot find module' (ts2307)
如果你的 TypeScript 构建时或 IDE 抱怨在导入时找不到模块或类型定义,请将以下内容添加到tsconfig.json
的 compilerOptions.types
数组中:
{
"compilerOptions": {
"types": ["vite-plugin-pwa/client"]
}
}
或者你可以添加以下引用到任何 d.ts
文件中(例如,在 vite-env.d.ts
或 global.d.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
来启用该属性:
useCredentials: true;
Service Worker errors on browser
查看新的 Vite 构建部分获取更多详细信息,以下描述的错误已在 v0.18.0+
中修复,并且不需要使用 iife
格式来构建您的 service worker。
如果您的 service worker 代码使用意外的 exports
编译(例如: export default require_sw();
),您可以将构建输出格式更改为 iife
,将以下代码添加到您的 pwa 配置:
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
中可用):
injectManifest: {
injectionPoint: undefined;
}
Service Worker Registration Errors
如果你想通知用户处理 Service Worker 注册错误,可以在 main.ts
或 main.js
中使用以下代码:
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
策略时:
workbox: {
maximumFileSizeToCacheInBytes: 3000000;
}
- 在使用
injectManifest
策略时:
injectManifest: {
maximumFileSizeToCacheInBytes: 3000000;
}
排除路由
如果你需要将某些路由排除在 service worker 拦截之外:
navigator / window
is undefined
如果你在构建应用程序时遇到了 navigator is undefined
或 window is undefined
错误,那么你的应用程序是在 SSR / SSG
环境下配置的
这种错误可能是由于使用了不支持SSR/SSG
的插件或库导致的:您的代码将在客户端和构建过程中的服务器端被调用,因此在构建应用程序时,服务器端的逻辑将被调用,但是在服务器端没有navigator/window
,所以它是undefined
。
第三方库
如果错误的原因是第三方库不知道 SSR / SSG
环境,解决错误的方法是在定义 window
时使用动态导入来导入它:
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
策略和支持 isReady
的router
(即路由器允许在当前组件路由完成加载时注册一个回调),您可以延迟 service worker 注册到路由器回调上。
例如,使用 vue-router
,您可以使用以下代码为 autoUpdate
策略注册 service worker
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
:
// 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
:
<!-- 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
组件:
// src/App.vue
<template>
...
<ClientOnly>
<ReloadPrompt />
</ClientOnly>
</template>
VitePress
你可以查看这个网站的 ReloadPrompt 组件来调用 PWA 虚拟模块:
<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 的示例文件夹中,您可以找到 preact
、 solid
和 svelte
的一些示例。
在开发环境中屏蔽 workbox-build 警告
如果您正在使用vite-plugin-pwa
的 generateSW
策略, 在开发环境中你可以使用suppressWarnings
选项来屏蔽workbox-build
的警告:
devOptions: {
suppressWarnings: true;
}
启用此选项, vite-plugin-pwa
开发插件将:
- 在
dev-dist
文件夹中生成一个空的suppress-warnings.js
文件。 - 修改
workbox.globPatterns
选项为 [*.js']