framework icon indicating copy to clipboard operation
framework copied to clipboard

feat(nuxt): payload prerendering support

Open pi0 opened this issue 2 years ago • 1 comments

🔗 Linked issue

#6411

❓ Type of change

  • [ ] 📖 Documentation (updates to the documentation or readme)
  • [ ] 🐞 Bug fix (a non-breaking change that fixes an issue)
  • [x] 👌 Enhancement (improving an existing functionality like performance)
  • [ ] ✨ New feature (a non-breaking change that adds functionality)
  • [ ] ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

📚 Description

This PR:

  • Adds new extension to renderer that by adding /_payload.js to the end of the URL, returning only payload chunk
  • Adds loadPayload(url, force?) composable
  • Adds prefetchPayload(url) composable
    • Server-side: Add link with modulepreload rel
    • Client-side: ~~calls usePayload(url) to fill in the cache~~ Same as server adds modulepreload to trigger browser prefetching in background
  • When using nuxt generate or prefetchPayload(url), it detect rendering mode based on headers and sets the x-nitro-prerender hint to prerender /[route]/_payload.js file
  • Add prerenderedAt to the payload when using prerendering or nuxt generate
  • Add isPrerender composable (check active payload)

Testing:

  • yarn nuxt build test/fixtures/basic
  • node test/fixtures/basic/.output/server/index.mjs
  • https://localhost:3000/random/a

Todo:

  • [x] Cache prerender payload to avoid duplicate render
  • [x] Replace payload from prerendered links to an external file
  • [x] Add prerender header for prerendered pages
  • [x] Load payload on navigation
  • [ ] Assign state on navigation
  • [ ] Payload filtering for unassigned keys
  • [ ] Run basic tests

📝 Checklist

  • [ ] I have linked an issue or discussion.
  • [ ] I have updated the documentation accordingly.

pi0 avatar Aug 09 '22 08:08 pi0

Deploy Preview for nuxt3-docs canceled.

Name Link
Latest commit 374429af968ba507ff4df0800c4c0ee6f658be89
Latest deploy log https://app.netlify.com/sites/nuxt3-docs/deploys/631c978483f016000846ff76

netlify[bot] avatar Aug 09 '22 08:08 netlify[bot]

Mind if I push a test suite later this evening before merging?

danielroe avatar Sep 07 '22 16:09 danielroe

Thanks for helping to add tests @danielroe ❤️ Regarding your notes:

enabling static in dev mode without the method I used in tests - user may have an API that can't be called from browser or relies on server-only api keys

Later, with route rules, we could predict which routes are prerendered/static to adjust behavior. But note that payload rendering is not only for static mode (ie: server API keys available during prerendering phase. that should work in production too and with API fallback)

process.env.prerender - presumably we'll set this somehow in nitropack whilst prerendering?

It is already added and released from nitropack which I've used. If it doesn't work, not only is a performance issue but a security issue because an attacker could fill the memory of server by abusing payload cache. I plan to improve it later with a shared LRU.

would be nice to deduplicate payloads - e.g. if you hard load /random/a then it should 'fill' the payload and not redownload it when navigating from a -> b -> a.

Not quite sure to understand this. Payload state is fresh per page and payload URL is unique. We don't download by with but use dynamic import. Browsers have caching mechanism for esm imports and don't redownload. (unless using new hash to force download a new payload). Also note that we are splitting data/state from initial payload (runtime config and other top level keys)

would be nice to have support for testing generated or hybrid sites in test-utils

Do you mind to open an issue to elaborate more about your idea about possible utils?

pi0 avatar Sep 10 '22 09:09 pi0