11

I need a bit of help understanding SSR in the context of sveltekit. I noticed that the load method is called both on the server and the client and I cannot wrap my head around this. I guess it is needed to initialize the state of the client-side component, but why not just pass the props resulting from the SSR to the client?

What if a database request needs to be done during SSR? Now that same database request is repeated from the client? What if that is not even possible? I understand that I can use browser from $app/env to run different code on the server and in the browser but what props do I return? Is there any way to pass data from the server-side invocation of load to the client-side invocation?

jpfollenius
  • 16,456
  • 10
  • 90
  • 156

1 Answers1

19

why not just pass the props resulting from the SSR to the client?

In order to do this, the props need to be serializable. You couldn't — for example — do something like this:

<script context="module">
  export async function load({ fetch }) {
    const data = await fetch('/data.json').then(r => r.json());
    const model = create_model(data);

    return {
      props: { model }
    };
  }
</script>

<script>
  export let model;
</script>

<h1>{$model.title}</h1>

Or you might need to dynamically import one component in one case, and a different component in another case, and pass that through as a prop.

There's another disadvantage to serializing the load output (which is what happened with SvelteKit's predecessor, Sapper) — in some cases, you might end up serializing a lot more data than you need to:

<script context="module">
  export async function load({ fetch }) {
    const compressed = await fetch('/compressed-data.json').then(r => r.json());
    const data = decompress(compressed);

    return {
      props: { data }
    };
  }
</script>

So SvelteKit runs load on both server and client. But it doesn't mean you're making unnecessary network requests. Anything you fetch in your load function is baked into the server-rendered HTML, meaning a) everything is contained in one request, b) the data used for server and client renders is guaranteed to be consistent, and c) any strings that appear in the fetched data and also appear in the markup are essentially 'free' because of gzip (or brotli).

What if a database request needs to be done during SSR?

You shouldn't be talking directly to the database in load, you should be creating an endpoint and requesting data with fetch. (We may add a method for auto-generating these endpoints in future, but it's not currently on the roadmap.)

Rich Harris
  • 28,091
  • 3
  • 84
  • 99
  • 1
    +1 Thanks a lot! The use of an endpoint and the fact that fetches from `load` are essentially only done on the server and then cached really clears things up for me. – jpfollenius Jun 10 '21 at 14:58
  • 3
    But what if you need to fetch with urql or apollo... then how do you pass the data? It does not use fetch... – Jonathan Nov 20 '21 at 23:19
  • 1
    I find ssr with svelte kit to be useless unless you doing unauthenticated routes. If you use localStorage for your jwt then you cant make authenticated requests to api using ssr. – chovy Mar 08 '22 at 18:54