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

proper way to show loading skeleton during client side navigation and having complete data in first page load #10541

Closed
amit13k opened this issue Aug 12, 2023 · 1 comment

Comments

@amit13k
Copy link

amit13k commented Aug 12, 2023

Describe the problem

I want to achieve the following,

  • On first page load +page.svelte should get all the required data so that it can be server side rendered
  • On client side navigation +page.svelte should receive promises that it can conveniently use in the await block. This will allow it to display loading spinners/skeleton animations while waiting for response.

Describe the proposed solution

If we see the alternatives that i have mentioned below, either the approach doesn't work on many platforms due to response buffering or there is small lag due to how sveltekit works.

I was wondering if somehow we can configure sveltekit to not execute +page.server.ts's load on client-side navigation, it would solve the problem completely. Maybe, it can be a new file name who's load function runs only on first/direct request.

Also, not sure if it is worth it to solve this and add more complexity but definitely it is not 100% ideal how it works now. Maybe other frameworks also work this way.

Alternatives considered

I have found two solutions along the lines of streaming promises,

  1. feat: stream non-essential data #8901 (comment) by conditionally awaiting the promises based on isDataRequest we can achieve the above. But on platforms that don't support streaming the response will be buffered and thus this will not work as intended.

  2. By using +page.server.ts and +page.ts in a specific way we can solve this.

TLDR for this approach: Almost perfect but there is a small lag for displaying skeleton on client side navigation because we always wait for +page.server.ts's load function to execute

We need to do the following,

  • create an endpoint that both +page.server.ts and +page.ts can use
  • if isDataRequest is true in +page.server.ts return empty response else call this endpoint and return response (if using the fetch from parameters this will avoid a network request on server)
  • in +page.ts check if we got a response from +page.server.ts and return it else perform the fetch to endpoint we created earlier and return a promise that +page.svelte can use.

I have created the working example of this approach here,
https://www.sveltelab.dev/jmkmzn1hqy5ecg6

Importance

nice to have

Additional Information

No response

@amit13k amit13k closed this as completed Aug 12, 2023
@amit13k
Copy link
Author

amit13k commented Aug 12, 2023

I realized that the universal load function (+page.ts) alone can fulfill this requirement.

// +page.ts
import { browser } from "$app/environment";
import type { PageLoad } from "./$types";

export const load = (async ({ fetch }) => {
  // it's important to use the included fetch so that the fetch is not run again in the browser
  const promise = new Promise((resolve, reject) => {
    fetch("/api/debug?message=Hello!")
      .then((res) => {
        resolve(res.json());
      })
      .catch((err) => {
        reject(err);
      });
  });

  return {
    streamed: {
      // await the promise if running on server
      lazyCritical: browser ? promise : await promise,
    },
  };
}) satisfies PageLoad;

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

1 participant