-
-
Notifications
You must be signed in to change notification settings - Fork 232
feat: add PWA web manifest (without service worker) #1181
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
37dcddb
abe9cea
2b9ac50
03daa2d
f9cee47
b73b57d
ba1f96c
d7e9e78
4d02840
54ad77b
b6f5ade
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| import { | ||
| cleanupOutdatedCaches, | ||
| createHandlerBoundToURL, | ||
| precacheAndRoute, | ||
| } from 'workbox-precaching' | ||
| import { clientsClaim } from 'workbox-core' | ||
| import { NetworkFirst, StaleWhileRevalidate } from 'workbox-strategies' | ||
| import { NavigationRoute, registerRoute } from 'workbox-routing' | ||
| import { CacheableResponsePlugin } from 'workbox-cacheable-response' | ||
| import { ExpirationPlugin } from 'workbox-expiration' | ||
|
|
||
| declare let self: ServiceWorkerGlobalScope | ||
|
|
||
| const cacheNames = ['npmx-packages', 'npmx-packages-code-and-docs', 'npmx-vercel-proxies'] as const | ||
|
|
||
| async function createRuntimeCaches() { | ||
| await Promise.all(cacheNames.map(c => caches.open(c))) | ||
| } | ||
| self.addEventListener('install', event => { | ||
| event.waitUntil(createRuntimeCaches()) | ||
| }) | ||
|
|
||
| self.skipWaiting() | ||
| clientsClaim() | ||
|
|
||
| cleanupOutdatedCaches() | ||
| precacheAndRoute(self.__WB_MANIFEST, { | ||
| urlManipulation: ({ url }) => { | ||
| const urls: URL[] = [] | ||
| // search use query params, we need to include here any page using query params | ||
| if (url.pathname.endsWith('_payload.json') || url.pathname.endsWith('/search')) { | ||
| const newUrl = new URL(url.href) | ||
| newUrl.search = '' | ||
| urls.push(newUrl) | ||
| } | ||
| return urls | ||
| }, | ||
| }) | ||
|
|
||
| // allow only fallback in dev: we don't want to cache anything | ||
| let allowlist: undefined | RegExp[] | ||
| if (import.meta.env.DEV) allowlist = [/^\/$/] | ||
|
|
||
| // deny api and server page calls | ||
| let denylist: undefined | RegExp[] | ||
| if (import.meta.env.PROD) { | ||
| denylist = [ | ||
| // search page | ||
| /^\/search$/, | ||
| /^\/search\?/, | ||
| /^\/~/, | ||
| /^\/org\//, | ||
| // api calls | ||
| /^\/api\//, | ||
| /^\/oauth\//, | ||
| /^\/package\//, | ||
| /^\/package-code\//, | ||
| /^\/package-docs\//, | ||
| /^\/_v\//, | ||
| /^\/opensearch\.xml$/, | ||
| // exclude sw: if the user navigates to it, fallback to index.html | ||
| /^\/service-worker\.js$/, | ||
| ] | ||
|
|
||
| registerRoute( | ||
| ({ sameOrigin, url }) => | ||
| sameOrigin && | ||
| (url.pathname.startsWith('/package/') || | ||
| url.pathname.startsWith('/org/') || | ||
| url.pathname.startsWith('/~') || | ||
| url.pathname.startsWith('/api/')), | ||
| new NetworkFirst({ | ||
| cacheName: cacheNames[0], | ||
| plugins: [ | ||
| new CacheableResponsePlugin({ statuses: [200] }), | ||
| new ExpirationPlugin({ maxEntries: 1000, maxAgeSeconds: 60 }), | ||
| ], | ||
| }), | ||
| ) | ||
| registerRoute( | ||
| ({ sameOrigin, url }) => | ||
| sameOrigin && | ||
| (url.pathname.startsWith('/package-docs/') || url.pathname.startsWith('/package-code/')), | ||
| new StaleWhileRevalidate({ | ||
| cacheName: cacheNames[1], | ||
| plugins: [ | ||
| new CacheableResponsePlugin({ statuses: [200] }), | ||
| new ExpirationPlugin({ maxEntries: 1000, maxAgeSeconds: 365 * 24 * 60 * 60 }), | ||
| ], | ||
| }), | ||
| ) | ||
| registerRoute( | ||
| ({ sameOrigin, url }) => sameOrigin && url.pathname.startsWith('/_v/'), | ||
| new NetworkFirst({ | ||
| cacheName: cacheNames[1], | ||
| plugins: [ | ||
| new CacheableResponsePlugin({ statuses: [200] }), | ||
| new ExpirationPlugin({ maxEntries: 100, maxAgeSeconds: 60 }), | ||
| ], | ||
| }), | ||
| ) | ||
| } | ||
|
|
||
| // to allow work offline | ||
| registerRoute(new NavigationRoute(createHandlerBoundToURL('/'), { allowlist, denylist })) |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -114,6 +114,13 @@ export default defineNuxtConfig({ | |||||
| '/_v/view': { proxy: 'https://npmx.dev/_vercel/insights/view' }, | ||||||
| '/_v/event': { proxy: 'https://npmx.dev/_vercel/insights/event' }, | ||||||
| '/_v/session': { proxy: 'https://npmx.dev/_vercel/insights/session' }, | ||||||
| // PWA manifest | ||||||
| '/manifest.webmanifest': { | ||||||
| headers: { | ||||||
| 'Content-Type': 'application/manifest+json', | ||||||
| 'Cache-Control': 'public, max-age=0, must-revalidate', | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not some minimal caching, e.g.:
Suggested change
?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The webmanifest should be always checked like the service worker. Once web manifest stable we can change the cache control header. |
||||||
| }, | ||||||
| }, | ||||||
| }, | ||||||
|
|
||||||
| experimental: { | ||||||
|
|
@@ -192,18 +199,51 @@ export default defineNuxtConfig({ | |||||
| }, | ||||||
| }, | ||||||
|
|
||||||
| $test: { | ||||||
| pwa: { | ||||||
| disable: true, | ||||||
| }, | ||||||
| }, | ||||||
|
|
||||||
| pwa: { | ||||||
| // Disable service worker | ||||||
| disable: true, | ||||||
| pwaAssets: { | ||||||
| config: false, | ||||||
| registerType: 'autoUpdate', | ||||||
| strategies: 'injectManifest', | ||||||
| srcDir: '.', | ||||||
| filename: 'service-worker.ts', | ||||||
| client: { | ||||||
| periodicSyncForUpdates: 3_600, // Check for updates every hour | ||||||
| }, | ||||||
| injectManifest: { | ||||||
| minify: process.env.VITE_DEV_PWA !== 'true', | ||||||
| sourcemap: process.env.VITE_DEV_PWA !== 'true', | ||||||
| enableWorkboxModulesLogs: process.env.VITE_DEV_PWA === 'true' ? true : undefined, | ||||||
| globPatterns: ['**/*.{js,json,css,html,txt,svg,png,ico,webp,woff,woff2,ttf,eot,otf,wasm}'], | ||||||
| globIgnores: ['manifest**.webmanifest'], | ||||||
| }, | ||||||
| devOptions: { | ||||||
| enabled: process.env.VITE_DEV_PWA === 'true', | ||||||
| type: 'module', | ||||||
| }, | ||||||
| manifest: { | ||||||
| id: '/', | ||||||
| scope: '/', | ||||||
| start_url: '/', | ||||||
| name: 'npmx', | ||||||
| short_name: 'npmx', | ||||||
| description: 'A fast, modern browser for the npm registry', | ||||||
| theme_color: '#0a0a0a', | ||||||
| background_color: '#0a0a0a', | ||||||
| orientation: 'portrait', | ||||||
| display: 'standalone', | ||||||
| display_override: ['window-controls-overlay'], | ||||||
| // categories: ['social', 'social networking', 'news'], | ||||||
| handle_links: 'preferred', | ||||||
| launch_handler: { | ||||||
| client_mode: ['navigate-existing', 'auto'], | ||||||
| }, | ||||||
| edge_side_panel: { | ||||||
| preferred_width: 480, | ||||||
| }, | ||||||
| icons: [ | ||||||
| { | ||||||
| src: 'pwa-64x64.png', | ||||||
|
|
||||||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a problem with the icon, it is square, but on other shapes of icons (for example, round ones), the edges are white, this needs to be fixed.
It would also be great to add a monochrome version of the icon to have this icon themed as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to change the svg icons again, will be fixed once the service worker fixed (search page)