SSR und SvelteKit

Einrichtung

SvelteKit rendert Routen standardmäßig mit SSR. Aus diesem Grund müssen Sie die Abfrage auf dem Server deaktivieren. Andernfalls wird Ihre Abfrage nach dem Senden des HTML an den Client weiterhin asynchron auf dem Server ausgeführt.

Der empfohlene Weg, dies zu erreichen, ist die Verwendung des browser Moduls von SvelteKit in Ihrem QueryClient Objekt. Dies deaktiviert nicht queryClient.prefetchQuery(), das in einer der unten aufgeführten Lösungen verwendet wird.

src/routes/+layout.svelte

svelte
<script lang="ts">
  import { browser } from '$app/environment'
  import { QueryClient, QueryClientProvider } from '@tanstack/svelte-query'

  const queryClient = new QueryClient({
    defaultOptions: {
      queries: {
        enabled: browser,
      },
    },
  })
</script>

<QueryClientProvider client={queryClient}>
  <slot />
</QueryClientProvider>
<script lang="ts">
  import { browser } from '$app/environment'
  import { QueryClient, QueryClientProvider } from '@tanstack/svelte-query'

  const queryClient = new QueryClient({
    defaultOptions: {
      queries: {
        enabled: browser,
      },
    },
  })
</script>

<QueryClientProvider client={queryClient}>
  <slot />
</QueryClientProvider>

Daten vorab abrufen

Svelte Query unterstützt zwei Methoden, um Daten auf dem Server vorab abzurufen und diese mit SvelteKit an den Client zu übergeben.

Wenn Sie die ideale SSR-Einrichtung sehen möchten, schauen Sie sich bitte das SSR-Beispiel an.

Verwendung von initialData

Zusammen mit SvelteKits load können Sie die serverseitig geladenen Daten in die initialData Option von createQuery übergeben.

src/routes/+page.ts

ts
export async function load() {
  const posts = await getPosts()
  return { posts }
}
export async function load() {
  const posts = await getPosts()
  return { posts }
}

src/routes/+page.svelte

svelte
<script>
  import { createQuery } from '@tanstack/svelte-query'
  import type { PageData } from './$types'

  export let data: PageData

  const query = createQuery({
    queryKey: ['posts'],
    queryFn: getPosts,
    initialData: data.posts,
  })
</script>
<script>
  import { createQuery } from '@tanstack/svelte-query'
  import type { PageData } from './$types'

  export let data: PageData

  const query = createQuery({
    queryKey: ['posts'],
    queryFn: getPosts,
    initialData: data.posts,
  })
</script>

Vorteile

  • Diese Einrichtung ist minimal und kann in einigen Fällen eine schnelle Lösung sein.
  • Funktioniert sowohl mit +page.ts/+layout.ts als auch mit +page.server.ts/+layout.server.ts Load-Funktionen.

Nachteile

  • Wenn Sie createQuery in einer Komponente tiefer im Baum aufrufen, müssen Sie initialData bis zu diesem Punkt weitergeben.
  • Wenn Sie createQuery mit derselben Abfrage an mehreren Stellen aufrufen, müssen Sie initialData an alle übergeben.
  • Es gibt keine Möglichkeit zu wissen, wann die Abfrage auf dem Server abgerufen wurde, daher basiert dataUpdatedAt und die Bestimmung, ob die Abfrage erneut abgerufen werden muss, stattdessen darauf, wann die Seite geladen wurde.

Verwendung von prefetchQuery

Svelte Query unterstützt das Vorabrufen von Abfragen auf dem Server. Mit dieser unten gezeigten Einrichtung können Sie Daten abrufen und sie in den QueryClientProvider übergeben, bevor sie an den Browser des Benutzers gesendet werden. Daher sind diese Daten bereits im Cache verfügbar und es erfolgt kein anfänglicher Abruf auf der Clientseite.

src/routes/+layout.ts

ts
import { browser } from '$app/environment'
import { QueryClient } from '@tanstack/svelte-query'

export async function load() {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: {
        enabled: browser,
      },
    },
  })

  return { queryClient }
}
import { browser } from '$app/environment'
import { QueryClient } from '@tanstack/svelte-query'

export async function load() {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: {
        enabled: browser,
      },
    },
  })

  return { queryClient }
}

src/routes/+layout.svelte

svelte
<script lang="ts">
  import { QueryClientProvider } from '@tanstack/svelte-query'
  import type { LayoutData } from './$types'

  export let data: LayoutData
</script>

<QueryClientProvider client={data.queryClient}>
  <slot />
</QueryClientProvider>
<script lang="ts">
  import { QueryClientProvider } from '@tanstack/svelte-query'
  import type { LayoutData } from './$types'

  export let data: LayoutData
</script>

<QueryClientProvider client={data.queryClient}>
  <slot />
</QueryClientProvider>

src/routes/+page.ts

ts
export async function load({ parent, fetch }) {
  const { queryClient } = await parent()

  // You need to use the SvelteKit fetch function here
  await queryClient.prefetchQuery({
    queryKey: ['posts'],
    queryFn: async () => (await fetch('/api/posts')).json(),
  })
}
export async function load({ parent, fetch }) {
  const { queryClient } = await parent()

  // You need to use the SvelteKit fetch function here
  await queryClient.prefetchQuery({
    queryKey: ['posts'],
    queryFn: async () => (await fetch('/api/posts')).json(),
  })
}

src/routes/+page.svelte

svelte
<script lang="ts">
  import { createQuery } from '@tanstack/svelte-query'

  // This data is cached by prefetchQuery in +page.ts so no fetch actually happens here
  const query = createQuery({
    queryKey: ['posts'],
    queryFn: async () => (await fetch('/api/posts')).json(),
  })
</script>
<script lang="ts">
  import { createQuery } from '@tanstack/svelte-query'

  // This data is cached by prefetchQuery in +page.ts so no fetch actually happens here
  const query = createQuery({
    queryKey: ['posts'],
    queryFn: async () => (await fetch('/api/posts')).json(),
  })
</script>

Vorteile

  • Serverseitig geladene Daten können ohne Prop-Drilling überall abgerufen werden.
  • Nach dem Rendern der Seite erfolgt kein anfänglicher Abruf auf der Clientseite, da der Abfrage-Cache alle Informationen über die Abfrage behält, einschließlich dataUpdatedAt.

Nachteile

  • Erfordert mehr Dateien für die anfängliche Einrichtung.
  • Funktioniert nicht mit +page.server.ts/+layout.server.ts Load-Funktionen (jedoch müssen APIs, die mit TanStack Query verwendet werden, ohnehin vollständig für den Browser freigelegt werden).