Skip to content

Expand documentation on SSR hydration with SvelteKit #68

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/src/manifests/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@
"editUrl": "/guides/query-filters.md"
},
{
"title": "SSR & Sapper",
"title": "SSR & SvelteKit",
"path": "/guides/ssr",
"editUrl": "/guides/ssr.md"
},
Expand Down Expand Up @@ -356,4 +356,4 @@
]
}
]
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}
}

90 changes: 87 additions & 3 deletions docs/src/pages/guides/ssr.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
id: ssr
title: SSR
title: SSR & SvelteKit
---

Svelte Query supports two ways of prefetching data on the server and passing that to the queryClient.
Expand All @@ -11,6 +11,90 @@ Svelte Query supports two ways of prefetching data on the server and passing tha
- Prefetch the query on the server, dehydrate the cache and rehydrate it on the client
- Requires slightly more setup up front

## Using Sapper
## Using SvelteKit

Coming soon !
### Using `initialData`

Together with SvelteKit's [`load`](https://kit.svelte.dev/docs#loading), you can pass the data you fetch to `useQuery`'s' `initialData` option:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Together with SvelteKit's [`load`](https://kit.svelte.dev/docs#loading), you can pass the data you fetch to `useQuery`'s' `initialData` option:
Together with SvelteKit's [`load`](https://kit.svelte.dev/docs#loading), you can pass the data you fetch to `useQuery`'s `initialData` option:


```markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```markdown
```svelte

<script context="module">
export async function load() {
const posts = await getPosts()
return { props: { posts } }
}
</script>

<script>
export let posts;
const queryResult = useQuery('posts', getPosts, { initialData: posts });
</script>
```

The setup is minimal and this can be a quick solution for some cases, but there are a **few tradeoffs to consider** when compared to the full approach:

- If you are calling `useQuery` in a component deeper down in the tree you need to pass the `initialData` down to that point
- If you are calling `useQuery` with the same query in multiple locations, you need to pass `initialData` to all of them
- There is no way to know at what time the query was fetched on the server, so `dataUpdatedAt` and determining if the query needs refetching is based on when the page loaded instead

### Using Hydration

Svelte Query supports prefetching multiple queries on the server in SvelteKit and then _dehydrating_ those queries to the queryClient. This means the server can prerender markup that is immediately available on page load and as soon as JS is available, Svelte Query can upgrade or _hydrate_ those queries with the full functionality of the library. This includes refetching those queries on the client if they have become stale since the time they were rendered on the server.

To support caching queries on the server and set up hydration:

- Create a new `QueryClient` instance
- Wrap your app component with `<QueryClientProvider>` and pass it the client instance
- Wrap your app component with `<Hydrate>` and pass it the `dehydratedState` prop from `pageProps`

```markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```markdown
```svelte

// __layout.svelte

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// __layout.svelte
// +layout.svelte

<script lang="ts">
import { QueryClient, QueryClientProvider, Hydrate } from '@sveltestack/svelte-query';
import { page } from '$app/stores';
const {dehydrateState} = $page.stuff;

const queryClient = new QueryClient();
</script>

<QueryClientProvider client={queryClient}>
<Hydrate state={dehydratedState}>
<slot />
</Hydrate>
</QueryClientProvider>
```

Now you are ready to prefetch some data in your pages with [`load`](https://kit.svelte.dev/docs#loading).

- Create a new `QueryClient` instance
- Prefetch the data using the clients `prefetchQuery` method and wait for it to complete
- Use `dehydrate` to dehydrate the query cache and pass it to the page via the `dehydratedState` prop. This is the same prop that the cache will be picked up from in your `__layout.svelte`

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Use `dehydrate` to dehydrate the query cache and pass it to the page via the `dehydratedState` prop. This is the same prop that the cache will be picked up from in your `__layout.svelte`
- Use `dehydrate` to dehydrate the query cache and pass it to the page via the `dehydratedState` prop. This is the same prop that the cache will be picked up from in your `+layout.svelte`


```markdown
// pages/posts.svelte

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// pages/posts.svelte
// pages/posts/+page.svelte

<script context="module">
import { dehydrate, QueryClient, useQuery } from 'react-query';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔


export async function load() {
const queryClient = new QueryClient()

await queryClient.prefetchQuery('posts', getPosts)

return {
stuff: {
dehydratedState: dehydrate(queryClient),
},
}
}
</script>
<script>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a mix of <script> and <script lang="ts">; it would be nice if it could all be <script lang="ts"> so it can be useful to both JavaScript users with /** @type {} */ and to TypeScript users with import type {}.

const queryResult = useQuery('posts', getPosts)

// This query was not prefetched on the server and will not start
// fetching until on the client, both patterns are fine to mix
Comment on lines +93 to +94

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// This query was not prefetched on the server and will not start
// fetching until on the client, both patterns are fine to mix
// This query was not prefetched on the server and will not start
// fetching until on the client; both patterns are fine to mix.

const otherQueryResult = useQuery('posts-2', getPosts)

</script>
```

As demonstrated, it's fine to prefetch some queries and let others fetch on the queryClient. This means you can control what content server renders or not by adding or removing `prefetchQuery` for a specific query.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
As demonstrated, it's fine to prefetch some queries and let others fetch on the queryClient. This means you can control what content server renders or not by adding or removing `prefetchQuery` for a specific query.
As demonstrated, it's fine to prefetch some queries and let others fetch on the queryClient. This means you can control what content the server renders or not by adding or removing `prefetchQuery` for a specific query.

11 changes: 6 additions & 5 deletions docs/src/pages/reference/hydration/HydrateComp.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ title: hydration/Hydrate

`hydration/Hydrate` adds a previously dehydrated state into the `queryClient` that would returned by running `useQueryCache`. If the client already contains data, the new queries will be intelligently merged based on update timestamp.

```js
import { Hydrate } from '@sveltestack/svelte-query/hydration'
```markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```markdown
```svelte

<script>
import { Hydrate } from '@sveltestack/svelte-query'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import { Hydrate } from '@sveltestack/svelte-query'
import { Hydrate } from '@sveltestack/svelte-query'

</script>

<Hydrate state={dehydratedState}>...</Hydrate>

function App() {
return <Hydrate state={dehydratedState}>...</Hydrate>
}
```

**Options**
Expand Down