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

True equivalent to getStaticProps? #1599

Closed
madeleineostoja opened this issue May 30, 2021 · 10 comments
Closed

True equivalent to getStaticProps? #1599

madeleineostoja opened this issue May 30, 2021 · 10 comments
Labels
documentation Improvements or additions to documentation

Comments

@madeleineostoja
Copy link

madeleineostoja commented May 30, 2021

Is your feature request related to a problem? Please describe.
The load function currently runs on both the server and the client, which means that you can't do anything that should be left to the server in it (eg: fetching data for static rendering). Instead you have to create an endpoint route and then fetch this as json in your load, which is a lot of boilerplate and bloat for a very common use-case.

Even with a JSON endpoint to do heavy lifting, every route on the client still has to make that request and wait for it to resolve before rendering when the page has already prerendered.

Describe the solution you'd like
A way to opt out of running load on the client, so it provides props either only for SSR or prerendering. I know this was previously considered for sapper, and I'd love to see it reach sveltekit. Either as an option on load, or a new function with a similar signature, like how NextJS has getStaticProps, etc.

Describe alternatives you've considered
The currently recommended pattern for this use-case is creating JSON endpoints for every single route that needs data, which for a static site generator type context with a CMS is every route. Not only is that a lot of boilerplate and crappy DX, but it has unnecessary performance implications during routing outlined above.

There are other workarounds to help reduce the issue — prefetching as much as possible, using maxage to cache already visited routes — but none actually fix the problem that shouldn't exist in the first place.

How important is this feature to you?
Unless I'm missing something this is a big drawback to using sveltekit as an SSG, which was my main use-case over the likes of NextJS and Gatsby.

@dummdidumm
Copy link
Member

dummdidumm commented May 30, 2021

Have you thought about using browser from $app/env to achieve this (https://kit.svelte.dev/docs#modules-$app-env)? If yes, what don't you like about using it?

..load(...) {
  if(!browser) {
   ...
  }
..

@madeleineostoja
Copy link
Author

madeleineostoja commented May 30, 2021

Ah, to be honest I hadn’t even thought of it 🤦🏻‍♀️

I guess a few drawbacks that come to mind are:

  • Every serverside import needing to be a dynamic import, which is more cumbersome and less readable (also not sure what the deal is with tree shaking etc with dynamic imports, though I guess it doesn’t matter much on a server)
  • If you’re only returning props inside a !browser check, does that mean that every page will 404 once the client tries to call load, since if it doesn’t return anything it falls through? Would you have to return an empty props object or something to fool it?

To be honest I don’t really understand why load has to be run on the client at all.

If it works then I guess that’s a solution! It all does feel a bit unintuitive, and I still think a dedicated way to provide server/pretender only data would be a step forward in DX for sveltekit

@madeleineostoja
Copy link
Author

So I can confirm that the !browser pattern doesn't work for load. Svelte calls load on the client, and if it doesn't have props returned then it falls through to a 404. Or, if you return an empty props object, it uses that instead of what was returned in SSR. Basically load has to return the same values on the server and the browser, so !browser checks are useless here.

@madeleineostoja
Copy link
Author

madeleineostoja commented May 30, 2021

Also even with a [page].json.ts endpoint to do the heavy data lifting and then fetching that endpoint in load, every route still has to wait for that request to resolve before rendering a new page, which is a completely unnecessary performance hit for a prerendered page.

Unless I'm missing something this is a potentially dealbreaking issue if there's no way to opt-out of calling load on the client. Especially for a static site generator type scenario, which again to me is the biggest use-case of sveltekit as a framework.

@benmccann
Copy link
Member

Even with a JSON endpoint to do heavy lifting, every route on the client still has to make that request and wait for it to resolve before rendering when the page has already prerendered.

I'm not sure about this statement. I think that it's either not true or I'm misunderstanding what you're saying. The reason SvelteKit reruns this logic on the client is that it's doing hydration. If you're not familiar with that term check out these docs I've proposed adding in one of the pending PRs. So, SvelteKit fetches data in load on the server and then it reruns load on the client to hydrate the client, but it does not refetch the data. The data has been sent down with the initial page and Svelte uses it instead of refetching it. Note that this logic is built into SvelteKit's fetch implementation so the one case this might not be true is if you're getting data without using fetch somehow. In that case I'd first recommend trying to use fetch in whatever data fetching you're doing

@madeleineostoja
Copy link
Author

madeleineostoja commented May 31, 2021

Oookay that makes much more sense. I didn't realise that svelte's fetch implementation would hydrate and re-use data sent from the server. I think this could use some clarification in the docs, I thought svelte's fetch was just a utility method for an isomorphic fetch.

I am using sveltekit's fetch implementation to fetch local .json.ts paths, but I'd only tested it in preview and dev since I'm still playing around with the best way to fetch data in my setup. After more testing I can see that it's working as intended, rehydrating almost instantly. So now I've just re-written my CMS integration to use a provided fetcher from load rather than the SDK I previously was using, making this mostly a non-issue for me personally. I mean I still don't need to call load for every fully static prerendered route in my site, but the perf impact of that is now negligible.

I still think an SSR-only load method would be a DX improvement, but sounds like I just misunderstood how load actually works.

Happy to close this, unless the docs should be clarified at all.

@dummdidumm dummdidumm added the documentation Improvements or additions to documentation label May 31, 2021
@alecandido
Copy link

Even with a JSON endpoint to do heavy lifting, every route on the client still has to make that request and wait for it to resolve before rendering when the page has already prerendered.

I'm not sure about this statement. I think that it's either not true or I'm misunderstanding what you're saying. The reason SvelteKit reruns this logic on the client is that it's doing hydration. If you're not familiar with that term check out these docs I've proposed adding in one of the pending PRs. So, SvelteKit fetches data in load on the server and then it reruns load on the client to hydrate the client, but it does not refetch the data. The data has been sent down with the initial page and Svelte uses it instead of refetching it. Note that this logic is built into SvelteKit's fetch implementation so the one case this might not be true is if you're getting data without using fetch somehow. In that case I'd first recommend trying to use fetch in whatever data fetching you're doing

Same problem here: from the docs I misunderstood how fetch is working and how should I use it in load. I wonder if something like this is also happening for #1660 .
Some more docs about the theme would be appreciated (since right now is only telling not to use secrets in load, but not suggesting to use endpoint and exploiting fetch).

So it would improve if the docs would suggest in the red box below context a suitable alternative, being:

  • make an endpoint, containing the credentialed external fetch
  • read carefully fetch red box, and do not worry about the second load run on client

@josefaidt
Copy link
Contributor

Chiming in from #1660 yes I was unaware of how fetch worked in this context. If that endpoint is pulling in markdown files or accessing an API layer that's only available at build time adding the if (browser) check will cause the page to error out after the fetch call inevitably fails. I've gotten around this by turning off hydration for those dynamic routes but it has some unintended side effects such as removing interactivity defined in parent layouts.

@benmccann
Copy link
Member

I just updated the docs essentially with the suggestion above #1599 (comment). Given that, I'll go ahead and close this in favor of #1660 which it fairly similar to this issue

@alecandido
Copy link

Thank you, @benmccann.

Another useful bit of information is contained in the prerender section: I was not aware of the behavior of endpoints during static generation (i.e. they are running and thus retrieved content is inlined).

This is actually not strictly related to the previous point, but it was relevant to my case (and I believe static generation to be quite a common case), so I'm simply leaving this info here if anyone will check this issue in the future.

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

No branches or pull requests

5 participants