diff --git a/examples/pwa-simple/.vitepress/config.ts b/examples/pwa-simple/.vitepress/config.ts index f4df30d..1248be8 100644 --- a/examples/pwa-simple/.vitepress/config.ts +++ b/examples/pwa-simple/.vitepress/config.ts @@ -1,6 +1,8 @@ import { defineConfig } from 'vitepress' import { withPwa } from '@vite-pwa/vitepress' +const base = '/' // '/vite-plugin-pwa/' + export default withPwa(defineConfig({ vite: { logLevel: 'info', @@ -8,6 +10,7 @@ export default withPwa(defineConfig({ __DATE__: `'${new Date().toISOString()}'`, }, }, + base, lang: 'en-US', title: 'VitePress PWA', description: 'Vite Plugin PWA Integration example for VitePress', @@ -33,8 +36,6 @@ export default withPwa(defineConfig({ }, pwa: { mode: 'development', - base: '/', - scope: '/', registerType: 'autoUpdate', // injectRegister: 'inline', includeAssets: ['favicon.svg'], @@ -64,6 +65,9 @@ export default withPwa(defineConfig({ workbox: { globPatterns: ['**/*.{css,js,html,svg,png,ico,txt,woff2}'], }, + experimental: { + includeAllowlist: true, + }, devOptions: { enabled: true, suppressWarnings: true, diff --git a/src/integration.ts b/src/integration.ts index 0f65f05..e5d68f8 100644 --- a/src/integration.ts +++ b/src/integration.ts @@ -81,9 +81,45 @@ export function withUserConfig(config: UserConfig) { return head } + let allowlist: RegExp[] | undefined + + if (pwa.strategies !== 'injectManifest' && pwa.experimental?.includeAllowlist === true) { + pwa.workbox = pwa.workbox ?? {} + // luckily, navigateFallbackAllowlist is a reference, so we can update it before generating SW + allowlist = pwa.workbox.navigateFallbackAllowlist = pwa.workbox.navigateFallbackAllowlist ?? [] + pwa.workbox.runtimeCaching = pwa.workbox.runtimeCaching ?? [] + // add offline support: without this, missing page will not work offline + pwa.workbox.runtimeCaching.push({ + urlPattern: ({ request, sameOrigin }) => { + return sameOrigin && request.mode === 'navigate' + }, + handler: 'NetworkOnly', + options: { + plugins: [{ + /* this callback will be called when the fetch call fails */ + handlerDidError: async () => Response.redirect('404', 302), + /* this callback will prevent caching the response */ + cacheWillUpdate: async () => null, + }], + }, + }) + } + vitePressConfig.buildEnd = async (siteConfig) => { await userBuildEnd?.(siteConfig) - api && !api.disabled && await api.generateSW() + if (api && !api.disabled) { + // add pages to allowlist: any page that is not in the allowlist will not work offline + if (typeof allowlist !== 'undefined') { + const base = siteConfig.site.base ?? '/' + for (const page of siteConfig.pages) { + if (page === 'index.md') + allowlist.push(new RegExp(`^${base}(.html)?$`)) + else + allowlist.push(new RegExp(`^${base}${page.replace(/\.md$/, '(.html)?')}$`)) + } + } + await api.generateSW() + } } return vitePressConfig diff --git a/src/types.ts b/src/types.ts index 1956c66..36f4ab7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,6 +1,16 @@ import type { VitePWAOptions } from 'vite-plugin-pwa' export interface PwaOptions extends Partial { + experimental?: { + /** + * When using `generateSW` strategy, include the logic to handle the `workbox.navigateFallbackAllowlist` option. + * + * @see https://github.com/vite-pwa/vitepress/issues/22 + * + * @default false + */ + includeAllowlist?: boolean + } } declare module 'vitepress' {