Skip to content

Conversation

@userquin
Copy link
Member

@userquin userquin commented Sep 23, 2023

This PR includes support for SSR Pages via custom runtime caching plugins using NetworkOnly or NetworkFirst handler:

  • any SSR page path will be included in the sw precache denylist entry with exact match, if includes dynamic route the plugin will include a wildcard regex instead
  • any SSR page path will include a custom handler
  • for all children in any not dynamic SSR parent route will be also included in the denylist and in the runtime caching entries
  • no dynamic pages can be cached, just enable the cache option, you can include cacheName and offlinePage

To run the playground, from root: nr dev:preview:build.

We need to:

  • handle dynamic routes like somepath-[someparam]
  • handle routeRules: vitesse-nuxt3 is using prerender and Elk is using routeRules instead prerender (traverse all pages applying the routeRules match to include/exclude them, maybe creating and using a radix3 router?)

The PR using eval to generate the runtimeCaching entry per route since we need to provide a few parameters, maybe we can use another approach.

┌───────────────────┬──────────────────┬───────────────────────────────────────────────┐
│ (iteration index) │       Key        │                    Values                     │
├───────────────────┼──────────────────┼───────────────────────────────────────────────┤
│         0         │   '/hi/:id()'    │       { exp: /^\/hi\//, dynamic: true }       │
│         1         │     '/list'      │      { exp: /^\/list$/, dynamic: false }      │
│         2         │ '/list/example2' │ { exp: /^\/list\/example2$/, dynamic: false } │
│         3         │ '/list/example'  │ { exp: /^\/list\/example$/, dynamic: false }  │
│         4         │  '/list/:id()'   │      { exp: /^\/list\//, dynamic: true }      │
└───────────────────┴──────────────────┴───────────────────────────────────────────────┘

imagen

? eval(`() => ({
urlPattern: ({ url, sameOrigin }) => sameOrigin && url.pathname.match(${regex}),
handler: 'NetworkFirst',
options: {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add purge on quota error

},
plugins: [{
handlerDidError: async () => Response.redirect(${JSON.stringify(offlinePage)}, 302),
cacheWillUpdate: async ({ response }) => response.status === 200 ? response : null
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prevent error here (response can be null/undefined when offline)?
cacheWillUpdate: async ({ response }) => response?.status === 200 ? response : null


const ssrPages: NuxtPage[] = []
let nitroOptions: NitroOptions | undefined
nuxt.hook('nitro:init', (nitro) => {
Copy link
Member Author

@userquin userquin Sep 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we can just remove the configuration here and configure the options in vite:extendConfig hook

@userquin
Copy link
Member Author

userquin commented Sep 24, 2023

This PR is too complex to be solved automatically, the runtime caching should be included by the user, there are a lot of configuration that can be included, for example:

  • routes group set with a custom cache configuration, another routes group set with another custom cache configuration
  • custom cache with isr or swr configuration: should use StaleWhileRevalidate with proper headers?
  • custom cache with Vary header
  • custom cache with custom expiration (related to first entry)
  • complex Nuxt precache and routeRules mix: we should traverse pages with a router to check if we need to include/exclude some specific routes
  • complex dynamic routes layout/naming (somepath-[someparam] with children)
  • sort routes in a subtree to include first non dynamic ones (similar logic included in vue/unplugin router)

@userquin
Copy link
Member Author

userquin commented Mar 26, 2025

we should use https://github.com/unjs/unrouting to extract dynamic routes patterns/paths

/cc @danielroe 🙏 @BobbieGoede (sorry for the ping ❤️ )

@GreyXor
Copy link

GreyXor commented May 9, 2025

@userquin Hi, just to confirm, does this mean that offline support isn't currently available when using nuxt generate (with SSR enabled by default)? That would explain why I can't get offline support on my statically generated site

@userquin
Copy link
Member Author

userquin commented May 9, 2025

No, the problem is about SSR pages where you cannot add those routes to the sw precaching manifest, that's, a page refresh on any SSR page when offline will show the default browser offline page.

This PR will try to add a custom runtime caching for SSR pages to avoid the browser offline page; we need to store SSR pages in a new cache to allow work when offline (won't work if the user doesn't navigate to those pages previously): the runtime caching will require to "parse" SSR pages adding the corresponding "regex" to the runtime caching to allow workbox intercept and cache the SSR pages content.

@GreyXor
Copy link

GreyXor commented May 9, 2025

ok thanks for these explanations.
So my SSR static PWA app that doesn't work offline is probably something else 👍 will debug more

@userquin
Copy link
Member Author

userquin commented May 9, 2025

ok thanks for these explanations. So my SSR static PWA app that doesn't work offline is probably something else 👍 will debug more

Check if there is some error when installing the sw, if you share in a new issue/discussion your configuration and the url I can check it

@GreyXor
Copy link

GreyXor commented May 13, 2025

ok thanks for these explanations. So my SSR static PWA app that doesn't work offline is probably something else 👍 will debug more

Check if there is some error when installing the sw, if you share in a new issue/discussion your configuration and the url I can check it

Thanks, the offline feature of my app is working but only for "/" page. Not the "/foo" and "/bar". I need to first visit them online, and only after it can work in offline mode. with nuxt generate full static SPA nitro pre-rended app.

There's a way to directly make all page work in offline mode ?
my app is generated via nuxt generate. so i have SSG+SSR enabled. it's a full static site. no server behind, the server is only used during generation for all pages

  pwa: {
    registerType: 'autoUpdate',
    workbox: {
      navigateFallback: "/",
      globPatterns: ['**/*.{js,css,html,png,PNG,svg,jpg,JPG,jpeg}'],
    },

@userquin
Copy link
Member Author

userquin commented May 13, 2025

Did you remove/unregister the sw and the storage when switching between prerender and SSR app? You may have the old sw there, try using private browsing.

@GreyXor
Copy link

GreyXor commented May 13, 2025

Did you remove/unregister the sw and the storage when switching between prerender and SSR app? You may have the old sw there, try using private browsing.

Yes pre-rended pages is not availabe offline even on fresh restart, sw and storage removed

@userquin
Copy link
Member Author

userquin commented May 13, 2025

Can you share the repo or some url where I can check it? Or just provide a minimal reproduction 🙏

EDIT: check if you're going offline before the sw is ready (the sw should be green in the devtools, that's, installed and activated once sw precaching downloaded)

I'm testing settings pages with elk.zone and seems to be working, maybe we need to review Nuxt hooks, from time to time there are small breaking changes for the integration: for context check https://github.com/vite-pwa/nuxt/blob/main/src/utils/module.ts#L309-L338

offline elk.zone settings page

imagen

Can you confirm you're using the Nuxt PWA integration instead just the PWA plugin?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants