Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preloading a store #47

Closed
johnnypea opened this issue Jan 16, 2023 · 7 comments
Closed

Preloading a store #47

johnnypea opened this issue Jan 16, 2023 · 7 comments

Comments

@johnnypea
Copy link

Firstly thank you for this superb store extension.

I would like to preload/prefetch the data in the store during the SSR. Is this the recommended way to do it?

import type { PageLoad } from './$types';
import { productsStore } from '$lib/stores/products';

export const load = (() => {
    productsStore.load();
}) satisfies PageLoad;
@Akolyte01
Copy link
Collaborator

I have not worked with this package in a sveltekit enivronment, so tbh I don't have experience with using it in SSR.

That seems like it should be fine, although in that case it looks like the page would load as soon as it kicks off the store loading, instead of when the store finishes loading.

@johnnypea
Copy link
Author

That seems like it should be fine, although in that case it looks like the page would load as soon as it kicks off the store loading, instead of when the store finishes loading.

Thanks. It's fine, I can still await the store, but it will give it a head start.

@mifegui
Copy link

mifegui commented Jan 22, 2023

As I understand 'preloading' doesn't happen as you seem to think it happens.

First SvelteKit loads a server-side rendered version of your page.
After it has been loaded and the user is seeing it, it will also (re)load the same-page on the client.

That means the load() function in +page.ts is processed two times. At the server and at the client.

That means you can't preload the client from the server.

More importantly, the load function that you showed is not doing what it should be doing.
I guess you are also doing await productStore.load() in +page.svelte.
Altough I am sure it won't preload anything in SSR it might do it in CSR.

The way the load function is meant to be used is

+page.ts

import type { PageLoad } from './$types';
import { productsStore } from '$lib/stores/products';

export const load = (async () => {
    return {
      'storeResult': await productsStore.load();
    }
}) satisfies PageLoad;

+page.svelte

<script>
export let data;
</script>

{data.storeResult}

That means the page will render with the store content.
No loading screen or await is necessary

Sometimes it is better to load your stuff at +page.svelte.
In that case I don't think there is a point in also putting it in the +page.ts load() function.

@Akolyte01
Copy link
Collaborator

☝️ Thanks for the explanation! If that's how it works then you aren't really getting much use out of the store, by my understanding. Sure you can access the data via storeResult, but if you try to use any of the other store features, such as deriving other stores from prodcutsStore, I think the productsStore would have to load from scratch client side?

Maybe it would be possible to load the store and then pass the entire store through in the page's load function?

@johnnypea
Copy link
Author

johnnypea commented Jan 23, 2023

@mifegui it works for me as intended I am just not sure it's the most effective way to do it. I fetch the data only once during "preloading" on server.

That means the load() function in +page.ts is processed two times. At the server and at the client.

Not always. The "load" function will re-run only when its data has changed (has been invalidated) https://kit.svelte.dev/docs/load#invalidation. See the official docs or https://www.okupter.com/blog/sveltekit-internals-load-function

That means you can't preload the client from the server.

Yes you can and it will be hydrated on client. https://kit.svelte.dev/docs/glossary#hydration

More importantly, the load function that you showed is not doing what it should be doing.
I guess you are also doing await productStore.load() in +page.svelte.
Altough I am sure it won't preload anything in SSR it might do it in CSR.

When I check the network activity I can see there is only one request. It is because I load the data from the store as they are already stored there and you don't have to call productsStore.load() on client side, you just have to subscribe to the store. That's what the store is for.

You don't have to do await productsStore.load() either because of this https://kit.svelte.dev/docs/load#promise-unwrapping Actually, you don't want to do that because you will halt the loading if the request takes long time.

@Akolyte01 you don't have to "pass" the store in the load function as you can access it directly from it's instance. That's how you actually use the store. https://svelte.dev/tutorial/writable-stores

Here you can see how it works with the "TanStack Svelte Query" (https://tanstack.com/query/v4/docs/svelte/overview) https://www.reddit.com/r/sveltejs/comments/10718ef/comment/j3kycpw/?utm_source=share&utm_medium=web2x&context=3

In that case I don't think there is a point in also putting it in the +page.ts load() function.

Sure there is. SSR preloading is generally used.

@mifegui
Copy link

mifegui commented Feb 3, 2023

@johnnypea your answer was very helpful. I did have some misunderstandings and the docs didnt have some of that stuff when I first read it, thanks!

That means you can't preload the client from the server.

Yes you can and it will be hydrated on client

By 'preload the client from the server' I mean the client using the same store that has already been loaded on the server. That can't happen as the store is created on the server and then again on the client. When hydrating the store is loaded again.

When I check the network activity I can see there is only one request.

By network activity you mean the f12 console right? That's the CSR request, you can see the SSR request by putting a console.log inside the store.load() function and watching for the log on the terminal running sveltekit

Also, didn't know about TanStack, looks like magic, very nice. The example at your first post doesn't work like TanStack though, on first-page-load the load() function will run both on server and client unless you disable csr or ssr. The value loaded on SSR will show until the page is hydrated, at that point the value loaded at CSR side will show.

This stackblitz example shows the SSR loaded value being overwritten by the CSR loaded value everytime you reload https://stackblitz.com/edit/sveltejs-kit-template-default-zgvwbq?file=src/lib/stores.ts

At this point i think I might have misunderstood what you meant by 'preload the data during SSR'...

Anyway

you don't have to "pass" the store in the load function as you can access it directly from it's instance. That's how you actually use the store. https://svelte.dev/tutorial/writable-stores

I did that, and then I found out
these discussions that I wasn`t aware off that make it not applicable to my use case. That's specific to sveltekit
sveltejs/kit#4339 (comment)
sveltejs/kit#8614 (comment) @Akolyte01 your suggestion is basically what this guy is recommending and is what I am doing now, ty!

Importing the store directly may cause security holes IF the store loads different data for different users.

So, anyway, now I create my stores at layout.ts and pass them down to be used (there are no global stores). I still preload them as you showed in the first post. (Which is very nice)

@Akolyte01
Copy link
Collaborator

Closing for now. Feel free to reopen if additional clarification is needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants