Skip to content

Commit abe9cea

Browse files
committed
chore: add service worker
1 parent 37dcddb commit abe9cea

4 files changed

Lines changed: 167 additions & 11 deletions

File tree

app/service-worker.ts

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import {
2+
cleanupOutdatedCaches,
3+
createHandlerBoundToURL,
4+
precacheAndRoute,
5+
} from 'workbox-precaching'
6+
import { clientsClaim } from 'workbox-core'
7+
import { NetworkFirst, StaleWhileRevalidate } from 'workbox-strategies'
8+
import { NavigationRoute, registerRoute } from 'workbox-routing'
9+
import { CacheableResponsePlugin } from 'workbox-cacheable-response'
10+
import { ExpirationPlugin } from 'workbox-expiration'
11+
12+
declare let self: ServiceWorkerGlobalScope
13+
14+
const cacheNames = ['npmx-packages', 'npmx-packages-code-and-docs', 'npmx-vercel-proxies'] as const
15+
16+
async function createRuntimeCaches() {
17+
await Promise.all(cacheNames.map(c => caches.open(c)))
18+
}
19+
self.addEventListener('install', event => {
20+
event.waitUntil(createRuntimeCaches())
21+
})
22+
23+
self.skipWaiting()
24+
clientsClaim()
25+
26+
cleanupOutdatedCaches()
27+
precacheAndRoute(self.__WB_MANIFEST, {
28+
urlManipulation: ({ url }) => {
29+
const urls: URL[] = []
30+
// search use query params, we need to include here any page using query params
31+
if (url.pathname.endsWith('_payload.json') || url.pathname.endsWith('/search')) {
32+
const newUrl = new URL(url.href)
33+
newUrl.search = ''
34+
urls.push(newUrl)
35+
}
36+
return urls
37+
},
38+
})
39+
40+
// allow only fallback in dev: we don't want to cache anything
41+
let allowlist: undefined | RegExp[]
42+
if (import.meta.env.DEV) allowlist = [/^\/$/]
43+
44+
// deny api and server page calls
45+
let denylist: undefined | RegExp[]
46+
if (import.meta.env.PROD) {
47+
denylist = [
48+
// search page
49+
/^\/search$/,
50+
// api calls
51+
/^\/api\//,
52+
/^\/oauth\//,
53+
/^\/package\//,
54+
/^\/package-code\//,
55+
/^\/package-docs\//,
56+
/^\/_v\//,
57+
/^\/opensearch\.xml$/,
58+
// exclude sw: if the user navigates to it, fallback to index.html
59+
/^\/service-worker\.js$/,
60+
]
61+
62+
registerRoute(
63+
({ sameOrigin, url }) => sameOrigin && url.pathname.startsWith('/package/'),
64+
new NetworkFirst({
65+
cacheName: cacheNames[0],
66+
plugins: [
67+
new CacheableResponsePlugin({ statuses: [200] }),
68+
new ExpirationPlugin({ maxEntries: 100, maxAgeSeconds: 60 }),
69+
],
70+
}),
71+
)
72+
registerRoute(
73+
({ sameOrigin, url }) =>
74+
sameOrigin &&
75+
(url.pathname.startsWith('/package-docs/') || url.pathname.startsWith('/package-code/')),
76+
new StaleWhileRevalidate({
77+
cacheName: cacheNames[1],
78+
plugins: [
79+
new CacheableResponsePlugin({ statuses: [200] }),
80+
new ExpirationPlugin({ maxEntries: 100, maxAgeSeconds: 365 * 24 * 60 * 60 }),
81+
],
82+
}),
83+
)
84+
registerRoute(
85+
({ sameOrigin, url }) => sameOrigin && url.pathname.startsWith('/_v/'),
86+
new NetworkFirst({
87+
cacheName: cacheNames[1],
88+
plugins: [
89+
new CacheableResponsePlugin({ statuses: [200] }),
90+
new ExpirationPlugin({ maxEntries: 100, maxAgeSeconds: 60 }),
91+
],
92+
}),
93+
)
94+
}
95+
96+
// to allow work offline
97+
registerRoute(new NavigationRoute(createHandlerBoundToURL('/'), { allowlist, denylist }))

nuxt.config.ts

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -199,21 +199,51 @@ export default defineNuxtConfig({
199199
},
200200
},
201201

202+
$test: {
203+
pwa: {
204+
disable: true,
205+
},
206+
},
207+
202208
pwa: {
203-
injectRegister: false,
209+
registerType: 'autoUpdate',
210+
strategies: 'injectManifest',
211+
srcDir: '.',
212+
filename: 'service-worker.ts',
204213
client: {
205-
// Disable service worker
206-
registerPlugin: false,
214+
installPrompt: true,
215+
periodicSyncForUpdates: 3_600, // Check for updates every hour
216+
},
217+
injectManifest: {
218+
minify: process.env.VITE_DEV_PWA !== 'true',
219+
enableWorkboxModulesLogs: process.env.VITE_DEV_PWA === 'true' ? true : undefined,
220+
globPatterns: ['**/*.{js,json,css,html,txt,svg,png,ico,webp,woff,woff2,ttf,eot,otf,wasm}'],
221+
globIgnores: ['manifest**.webmanifest'],
207222
},
208223
devOptions: {
209-
enabled: true,
224+
enabled: process.env.VITE_DEV_PWA === 'true',
225+
type: 'module',
210226
},
211227
manifest: {
228+
id: '/',
229+
scope: '/',
230+
start_url: '/',
212231
name: 'npmx',
213232
short_name: 'npmx',
214233
description: 'A fast, modern browser for the npm registry',
215234
theme_color: '#0a0a0a',
216235
background_color: '#0a0a0a',
236+
orientation: 'portrait',
237+
display: 'standalone',
238+
display_override: ['window-controls-overlay'],
239+
// categories: ['social', 'social networking', 'news'],
240+
handle_links: 'preferred',
241+
launch_handler: {
242+
client_mode: ['navigate-existing', 'auto'],
243+
},
244+
edge_side_panel: {
245+
preferred_width: 480,
246+
},
217247
icons: [
218248
{
219249
src: 'pwa-64x64.png',

package.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"build:lunaria": "node ./lunaria/lunaria.ts",
1515
"build:test": "NODE_ENV=test pnpm build",
1616
"dev": "nuxt dev",
17+
"dev:pwa": "VITE_DEV_PWA=true nuxt dev",
1718
"dev:docs": "pnpm run --filter npmx-docs dev --port=3001",
1819
"i18n:check": "node scripts/compare-translations.ts",
1920
"i18n:check:fix": "node scripts/compare-translations.ts --fix",
@@ -71,7 +72,7 @@
7172
"@unocss/preset-wind4": "66.6.0",
7273
"@upstash/redis": "1.36.1",
7374
"@vite-pwa/assets-generator": "1.0.2",
74-
"@vite-pwa/nuxt": "1.1.0",
75+
"@vite-pwa/nuxt": "1.1.1",
7576
"@voidzero-dev/vite-plus-core": "0.0.0-833c515fa25cef20905a7f9affb156dfa6f151ab",
7677
"@vueuse/core": "14.2.0",
7778
"@vueuse/integrations": "14.2.0",
@@ -105,7 +106,14 @@
105106
"vite-plugin-pwa": "1.2.0",
106107
"vite-plus": "0.0.0-833c515fa25cef20905a7f9affb156dfa6f151ab",
107108
"vue": "3.5.27",
108-
"vue-data-ui": "3.14.9"
109+
"vue-data-ui": "3.14.9",
110+
"workbox-build": "7.4.0",
111+
"workbox-cacheable-response": "7.4.0",
112+
"workbox-core": "7.4.0",
113+
"workbox-expiration": "7.4.0",
114+
"workbox-precaching": "7.4.0",
115+
"workbox-routing": "7.4.0",
116+
"workbox-strategies": "7.4.0"
109117
},
110118
"devDependencies": {
111119
"@e18e/eslint-plugin": "0.1.4",

pnpm-lock.yaml

Lines changed: 26 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)