kit icon indicating copy to clipboard operation
kit copied to clipboard

Page/layout load functions running twice on initial page load

Open pilcrowonpaper opened this issue 3 years ago • 6 comments

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.

pilcrowonpaper avatar Sep 11 '22 00:09 pilcrowonpaper

This is intended behaviour:

  • it's not uncommon for load to return objects that can't be serialized (such as component constructors)
  • data returned from a load function is often somewhat larger than the source data it depends on. For example if a load function 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.

Rich-Harris avatar Sep 20 '22 01:09 Rich-Harris

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.

pooledge avatar Sep 20 '22 07:09 pooledge

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.

dummdidumm avatar Sep 20 '22 08:09 dummdidumm

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

pooledge avatar Sep 20 '22 08:09 pooledge

Do you have a minimum reproducible? Could you open a separate issue for that?

dummdidumm avatar Sep 20 '22 09:09 dummdidumm

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?

pooledge avatar Sep 20 '22 09:09 pooledge

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

llui85 avatar Sep 26 '22 22:09 llui85

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.

codingawayy avatar Oct 02 '22 10:10 codingawayy

Closing as the docs address this now

dummdidumm avatar Dec 12 '23 19:12 dummdidumm