swr does not return cached html
I use these routerules
$production: {
routeRules: {
'/**': {
cache: {
swr: true,
staleMaxAge: 600,
},
},
},
},
But on client side navigation the pages are still very slow. Initial Load is fast. Why is that the case and is it normal that the page still needs to wait for all fetches on the page when navigating on swr sites?
11 Replies
Hi @Samuelreichoer. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
----------------------
Based on the knowledge sources provided, I can help explain what's happening with your SWR configuration and client-side navigation.
Understanding the Issue
The behavior you're experiencing is actually expected. SWR (Stale-While-Revalidate) caching in Nuxt applies to server-side rendering, not client-side navigation. According to Route Rules in Nuxt - SSR, SSG, ISR and more, route rules like SWR affect how the server caches and serves HTML responses.
When you navigate client-side (clicking links within your app), Nuxt doesn't fetch the cached HTML from the server. Instead, it performs client-side navigation using Vue Router, which means:
1. The initial page load is fast because the server returns cached HTML
2. Client-side navigation is slower because it needs to re-execute all data fetching logic (
useFetch, useAsyncData, etc.) on the client
Solutions for Faster Client-Side Navigation
To improve client-side navigation performance, you should focus on payload caching. According to feat(nuxt): enable payload extraction for ISR/SWR routes, payload extraction can now be enabled for SWR routes, which allows:
- Navigation to use cached payloads
- Avoiding re-making API calls with every client-side navigation
- CDNs to cache the payload files alongside the HTML
Additionally, you can use the getCachedData option with useAsyncData and useFetch to implement client-side caching. As explained in Nuxt 3.8 - Client-side caching with getCachedData, this function can avoid superfluous API calls and cache data for visitors on the client.
Summary
Yes, it's normal that pages need to wait for all fetches during client-side navigation with SWR route rules, as SWR primarily optimizes server-side caching. To improve client-side navigation performance, consider implementing payload extraction and using getCachedData for your data fetching composables.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@1065266379382587422> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@kapa.ai What's the point of Nuxt Link then performance wise
Let me check the knowledge base for you again. One moment! :books:
----------------------
Based on the knowledge sources,
<NuxtLink> provides several important performance benefits, even in the context of client-side navigation:
Smart Prefetching
According to docs: add performance best practices section, <NuxtLink> offers smart prefetching capabilities. This means that when links are visible in the viewport or when users hover over them, Nuxt can prefetch the necessary resources in advance.
The docs: add description for prefetch and other details of NuxtLink PR specifically adds detailed documentation about this prefetching behavior, which was adapted from Nuxt 2's implementation.
How Prefetching Works
Based on fix(nuxt): avoid invoke shouldPrefetch on the server side, <NuxtLink> determines whether to prefetch based on interaction events like onPointerenter and onFocus. This allows the component to preload route components and data before the user actually clicks the link.
Payload Prefetching
According to perf(nuxt): use browser cache for payloads, when you prefetch with <NuxtLink>, it can prefetch payloads (the data needed for the page) and leverage browser caching. This addresses the issue you mentioned about slow client-side navigation - when properly configured, <NuxtLink> can prefetch the payload data so it's already available when the user navigates.
The PR notes that this "should dramatically improve memory usage on large or content-driven websites" and allows the browser to manage cache efficiently.
Summary
The performance benefit of <NuxtLink> is that it anticipates navigation and prefetches resources before the user clicks, making the actual navigation feel instant. This is separate from SWR caching, which optimizes server-side responses.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@1065266379382587422> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@kapa.ai How can I see that prefetching actually works, when scrolling over my nuxt links no fetches happen in my network tab
Let me check the knowledge base for you again. One moment! :books:
----------------------
Based on the knowledge sources, I can help explain what you should be looking for when checking if prefetching is working.
Understanding Payload Prefetching
According to perf(nuxt): use browser cache for payloads, the prefetching behavior has been updated to work differently than you might expect:
"previously on prefetch the payload was already loaded into memory, not just fetched. Instead, we nowThis means that whenhint to browser to prefetch a URLwe still import the URL but do not set it in memory"
<NuxtLink> prefetches, it imports the URL but doesn't immediately load it into memory. The prefetch leverages browser caching, so when you actually navigate, it forces using the browser cache.
What to Look For
Unfortunately, the knowledge sources don't explicitly detail what you should see in the Network tab to verify prefetching is working. However, based on the implementation described in perf(nuxt): use browser cache for payloads, the prefetch mechanism now relies on browser cache rather than making visible network requests that load data into memory immediately.
Checking Prefetch Configuration
According to fix(nuxt): avoid invoke shouldPrefetch on the server side, <NuxtLink> determines whether to prefetch based on interaction events. The prefetching should trigger on onPointerenter and onFocus events on the client side.
I'm sorry, but the knowledge sources don't provide specific guidance on how to verify prefetching in the Network tab or DevTools. You may need to check the Nuxt DevTools payload tab or browser cache to confirm that prefetching is functioning, but the exact method isn't detailed in the available documents.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@1065266379382587422> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@kapa.ai Ich hab mir das jetzt so gebaut, useCraftFetch benutzt useFetch im Hintergrund.
export async function useCraftCachedFetch<ResT = unknown>(url: string) {
const { data, error } = await useCraftFetch<ResT>(url, {
getCachedData(key, nuxtApp) {
if (useCraftPreview().isPreview) return
return nuxtApp.payload.data[key] || nuxtApp.static.data[key]
},
})
return { data, error }
}
Mein Problem ist jetzt nur noch, das ich diese Funktion mit await und ohne benutzen will, das geht so noch nicht
Let me check the knowledge base for you again. One moment! :books:
----------------------
Basierend auf den Knowledge Sources kann ich dir erklären, warum deine Funktion nicht sowohl mit als auch ohne
await funktioniert.
Das Problem
Laut How to properly wrap useFetch to access reactivity? liegt das Problem daran, dass async Funktionen immer native Promises zurückgeben. useFetch und useAsyncData geben jedoch "augmented promises" zurück - Promises, die zusätzliche reaktive Eigenschaften wie data, pending, error etc. haben.
Wie in Why can I access the return value of useFetch without await keyword? erklärt wird, macht useFetch intern folgendes:
Das Promise wird mit den reaktiven Eigenschaften "gemischt", sodass man es mit oder ohne await verwenden kann.
Die Lösung
Laut How to properly wrap useFetch to access reactivity? solltest du deine Funktion nicht als async deklarieren und stattdessen direkt das Ergebnis von useFetch zurückgeben:
Wenn du asynchrone Operationen vor dem useFetch-Aufruf durchführen musst (wie in deinem Fall möglicherweise nicht), solltest du diese in die onRequest Option verschieben, wie in How to properly wrap useFetch to access reactivity? empfohlen wird.
Wichtiger Hinweis: Die Knowledge Sources weisen darauf hin, dass die Verwendung ohne await nicht in der offiziellen Dokumentation aufgeführt ist und sich daher ohne Vorankündigung ändern kann.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@1065266379382587422> Kapa.ai is still learning and improving, please let me know how I did by reacting below.