kit
kit copied to clipboard
Page/layout load functions running twice on initial page load
Describe the bug
This is either a "feature" request or an issue with the docs.
On initial page load (server-side navigation), page and layout load functions run once during SSR (server) and once before hydration. I'm sure this is intended behavior but I don't see why it is. This blocks the hydration process, and if load functions can return different results, the page will look/act different before and after hydration. Initial page load are part of server side navigation and not client side navigation, so one would think that load functions will only run once in the server and reuse that the hydration process in the client. The result of server load functions are sent to the browser inside hydrate.data so I don't see why we can't do the same for normal load functions as well.
If there's a reason to keep this behavior, it would be great if the docs explained this more clearly. Right now it states where each load functions run but not when.
Reproduction
none.
Logs
none.
System Info
none.
Severity
serious, but I can work around it
Additional Information
none.
This is intended behaviour:
- it's not uncommon for
loadto return objects that can't be serialized (such as component constructors) - data returned from a
loadfunction is often somewhat larger than the source data it depends on. For example if aloadfunction fetches some CSV data then calculates rolling averages and other derived values, 50kb of data can very quickly become 500kb or more. The reverse is very rarely true (and if it is true that the source data is large, that's a problem you need to solve anyway since it will affect client-side navigation)
if load functions can return different results, the page will look/act different before and after hydration
This is a feature, not a bug. Data consistency is guaranteed by SvelteKit inlining fetched data into the HTML, but if the load function returns something different when browser === true then we want to respect that.
I am sorry, now this is a bit confusing.
Current documentation states:
during hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request
So, how do I debug a post-405 app to actually prevent this network request?
This is intended behaviour
Or does this mean it is a lost battle anyway? Isn't it primarily a developer's task to ensure this consistency instead of SK kinda handicapping everyone with another hundreds ms.
What do I miss? Thanks.
So, how do I debug a post-405 app to actually prevent this network request?
This isn't anything new, it has always been like this in SvelteKit. I'm not sure what you mean by "debug to actually prevent this network request", but you can look in the network tab when loading the page to see that these requests are not made twice if you use the fetch function provided to load.
This is intended behaviour
Or does this mean it is a lost battle anyway? Isn't it primarily a developer's task to ensure this consistency instead of SK kinda handicapping everyone with another hundreds ms.
Not sure what you mean by this. As Rich pointed out, this is a feature, you as a developer can chose to guarantee consistency or return something different on the client, depending on your use case. You can also chose to not use the +page.js load function and instead only use load in +page.server.js, which means nothing is run twice. You can also choose to disable JavaScript completely if you are concerned about the JavaScript cost by adding export const csr = false to your root +layout.js to disable it for the entire app, or adding it to +page.js to disable JS for specific pages.
Thank you for clarification, Simon!
Regarding debugging, I came here solely because, despite using fetch provided by load, I cannot get rid of a browser request and I surely don't want to have a +page.server.js
Do you have a minimum reproducible? Could you open a separate issue for that?
Now, that I know I can prevent the duplicate request, I was able to narrow it down to the fact, that it occurs if endpoint URL is absolute, e.g. http://localhost:3000/api/v1/somedata instead of /api/v1/somedata
Since the only mention is that
it can make relative requests on the server
Maybe worth mentioning in docs or did I miss it?
What would be the best way to ensure that the load function only runs on the server once, if it can be guaranteed that the data can be safely serialized? I'm struggling to find a way to check if the page has been hydrated - is there a lifecycle function I can hook into?
To be clear, I'm trying to make one request on the server only if a route is being initially loaded, but on the client-side if that route is navigated to.
Edit: Never mind, I figured it out - turns out you can use LoadEvent.fetch instead of window.fetch
I am facing the exact same problem. The following code results in 2 HTTP requests - one from the server and one from the browser. Based on the docs I understood that the browser request shouldn't happen?
/** @type {import('@sveltejs/kit').Load} */
export async function load({ fetch }) {
var x = await fetch('http://localhost:3000/api');
console.log(x);
return {
x: x
};
}
Changing the URL to a relative one (await fetch('/api')) does not help.
Closing as the docs address this now