Skip to content

Commit 34ad882

Browse files
feat: Svelte implementation of client persistence (#5928)
Co-authored-by: Lachlan Collins <[email protected]>
1 parent 4eae428 commit 34ad882

31 files changed

+1205
-304
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// @ts-check
2+
3+
/** @type {import('eslint').Linter.Config} */
4+
const config = {
5+
extends: ['plugin:svelte/recommended'],
6+
parserOptions: {
7+
tsconfigRootDir: __dirname,
8+
project: './tsconfig.json',
9+
extraFileExtensions: ['.svelte'],
10+
},
11+
ignorePatterns: ['*.config.*', '*.setup.*', '**/dist/*'],
12+
overrides: [
13+
{
14+
files: ['*.svelte'],
15+
parser: 'svelte-eslint-parser',
16+
parserOptions: {
17+
parser: '@typescript-eslint/parser',
18+
},
19+
},
20+
],
21+
}
22+
23+
module.exports = config
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
{
2+
"name": "@tanstack/svelte-query-persist-client",
3+
"version": "5.0.0-beta.20",
4+
"description": "Svelte bindings to work with persisters in TanStack/svelte-query",
5+
"author": "Lachlan Collins",
6+
"license": "MIT",
7+
"repository": "tanstack/query",
8+
"homepage": "https://tanstack.com/query",
9+
"funding": {
10+
"type": "github",
11+
"url": "https://github.com/sponsors/tannerlinsley"
12+
},
13+
"type": "module",
14+
"types": "dist/index.d.ts",
15+
"module": "dist/index.js",
16+
"svelte": "./dist/index.js",
17+
"exports": {
18+
".": {
19+
"types": "./dist/index.d.ts",
20+
"svelte": "./dist/index.js",
21+
"import": "./dist/index.js",
22+
"default": "./dist/index.js"
23+
},
24+
"./package.json": "./package.json"
25+
},
26+
"files": [
27+
"dist",
28+
"src"
29+
],
30+
"scripts": {
31+
"clean": "rimraf ./dist && rimraf ./coverage",
32+
"test:types": "svelte-check --tsconfig ./tsconfig.json",
33+
"test:eslint": "eslint --ext .svelte,.ts ./src",
34+
"test:lib": "vitest run --coverage",
35+
"test:lib:dev": "pnpm run test:lib --watch",
36+
"test:build": "publint --strict",
37+
"build": "svelte-package --input ./src --output ./dist"
38+
},
39+
"dependencies": {
40+
"@tanstack/query-persist-client-core": "workspace:*"
41+
},
42+
"devDependencies": {
43+
"@sveltejs/package": "^2.2.0",
44+
"@sveltejs/vite-plugin-svelte": "^2.4.2",
45+
"@tanstack/svelte-query": "workspace:*",
46+
"@testing-library/svelte": "^4.0.3",
47+
"eslint-plugin-svelte": "^2.32.0",
48+
"svelte": "^4.0.0",
49+
"svelte-check": "^3.4.4"
50+
},
51+
"peerDependencies": {
52+
"@tanstack/svelte-query": "workspace:^",
53+
"svelte": ">=3 <5"
54+
}
55+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<script lang="ts">
2+
import { onDestroy } from 'svelte'
3+
import { persistQueryClient } from '@tanstack/query-persist-client-core'
4+
import {
5+
QueryClientProvider,
6+
setIsRestoringContext,
7+
} from '@tanstack/svelte-query'
8+
import { writable } from 'svelte/store'
9+
import type { PersistQueryClientOptions } from '@tanstack/query-persist-client-core'
10+
import type { QueryClient } from '@tanstack/svelte-query'
11+
12+
export let client: QueryClient
13+
export let onSuccess: () => Promise<unknown> | unknown = () => undefined
14+
export let persistOptions: Omit<PersistQueryClientOptions, 'queryClient'>
15+
16+
const isRestoring = writable(true)
17+
setIsRestoringContext(isRestoring)
18+
$: {
19+
let isStale = false
20+
isRestoring.set(true)
21+
const [unsubscribe, promise] = persistQueryClient({
22+
...persistOptions,
23+
queryClient: client,
24+
})
25+
promise.then(async () => {
26+
if (!isStale) {
27+
try {
28+
await onSuccess()
29+
} finally {
30+
isRestoring.set(false)
31+
}
32+
}
33+
})
34+
onDestroy(() => {
35+
isStale = true
36+
unsubscribe()
37+
})
38+
}
39+
</script>
40+
41+
<QueryClientProvider {client}>
42+
<slot />
43+
</QueryClientProvider>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<script lang="ts">
2+
import { createQuery } from '@tanstack/svelte-query'
3+
import { get } from 'svelte/store'
4+
import { sleep } from '../utils'
5+
import type { Writable } from 'svelte/store'
6+
7+
export let key: Array<string>
8+
export let states: Writable<Array<string>>
9+
10+
const state = createQuery({
11+
queryKey: key,
12+
queryFn: async () => {
13+
states.update((s) => [...s, 'fetching'])
14+
await sleep(10)
15+
states.update((s) => [...s, 'fetched'])
16+
return 'fetched'
17+
},
18+
})
19+
20+
let data = get(state).data
21+
let fetchStatus = get(state).fetchStatus
22+
state.subscribe((s) => {
23+
data = s.data
24+
fetchStatus = s.fetchStatus
25+
})
26+
</script>
27+
28+
<div>
29+
<h1>{data}</h1>
30+
<h2>fetchStatus: {fetchStatus}</h2>
31+
</div>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<script lang="ts">
2+
import PersistQueryClientProvider from '../../PersistQueryClientProvider.svelte'
3+
import AwaitOnSuccess from './AwaitOnSuccess.svelte'
4+
import type { QueryClient } from '@tanstack/svelte-query'
5+
import type { PersistQueryClientOptions } from '@tanstack/query-persist-client-core'
6+
import type { Writable } from 'svelte/store'
7+
8+
export let queryClient: QueryClient
9+
export let persistOptions: Omit<PersistQueryClientOptions, 'queryClient'>
10+
export let key: Array<string>
11+
export let onSuccess: () => Promise<void>
12+
export let states: Writable<Array<string>>
13+
</script>
14+
15+
<PersistQueryClientProvider client={queryClient} {persistOptions} {onSuccess}>
16+
<AwaitOnSuccess {key} {states} />
17+
</PersistQueryClientProvider>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<script lang="ts">
2+
import { createQuery } from '@tanstack/svelte-query'
3+
import { get } from 'svelte/store'
4+
import { sleep } from '../utils'
5+
import type { Writable } from 'svelte/store'
6+
import type { StatusResult } from '../utils'
7+
8+
export let key: Array<string>
9+
export let states: Writable<Array<StatusResult<string>>>
10+
export let fetched: Writable<boolean>
11+
12+
const state = createQuery({
13+
queryKey: key,
14+
queryFn: async () => {
15+
fetched.set(true)
16+
await sleep(10)
17+
return 'fetched'
18+
},
19+
20+
staleTime: Infinity,
21+
})
22+
23+
let data = get(state).data
24+
let fetchStatus = get(state).fetchStatus
25+
state.subscribe((s) => {
26+
states.update((prev) => [
27+
...prev,
28+
{ status: s.status, data: s.data, fetchStatus: s.fetchStatus },
29+
])
30+
data = s.data
31+
fetchStatus = s.fetchStatus
32+
})
33+
</script>
34+
35+
<div>
36+
<h1>data: {data ?? 'null'}</h1>
37+
<h2>fetchStatus: {fetchStatus}</h2>
38+
</div>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<script lang="ts">
2+
import PersistQueryClientProvider from '../../PersistQueryClientProvider.svelte'
3+
import FreshData from './FreshData.svelte'
4+
import type { QueryClient } from '@tanstack/svelte-query'
5+
import type { PersistQueryClientOptions } from '@tanstack/query-persist-client-core'
6+
import type { Writable } from 'svelte/store'
7+
import type { StatusResult } from '../utils'
8+
9+
export let queryClient: QueryClient
10+
export let persistOptions: Omit<PersistQueryClientOptions, 'queryClient'>
11+
export let key: Array<string>
12+
export let states: Writable<Array<StatusResult<string>>>
13+
export let fetched: Writable<boolean>
14+
</script>
15+
16+
<PersistQueryClientProvider client={queryClient} {persistOptions}>
17+
<FreshData {key} {states} {fetched} />
18+
</PersistQueryClientProvider>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<script lang="ts">
2+
import { createQuery } from '@tanstack/svelte-query'
3+
import { get } from 'svelte/store'
4+
import { sleep } from '../utils'
5+
import type { Writable } from 'svelte/store'
6+
import type { StatusResult } from '../utils'
7+
8+
export let key: Array<string>
9+
export let states: Writable<Array<StatusResult<string>>>
10+
11+
const state = createQuery({
12+
queryKey: key,
13+
queryFn: async () => {
14+
await sleep(10)
15+
return 'fetched'
16+
},
17+
18+
initialData: 'initial',
19+
// make sure that initial data is older than the hydration data
20+
// otherwise initialData would be newer and takes precedence
21+
initialDataUpdatedAt: 1,
22+
})
23+
24+
let data = get(state).data
25+
let fetchStatus = get(state).fetchStatus
26+
state.subscribe((s) => {
27+
states.update((prev) => [
28+
...prev,
29+
{ status: s.status, data: s.data, fetchStatus: s.fetchStatus },
30+
])
31+
data = s.data
32+
fetchStatus = s.fetchStatus
33+
})
34+
</script>
35+
36+
<div>
37+
<h1>{data}</h1>
38+
<h2>fetchStatus: {fetchStatus}</h2>
39+
</div>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<script lang="ts">
2+
import PersistQueryClientProvider from '../../PersistQueryClientProvider.svelte'
3+
import InitialData from './InitialData.svelte'
4+
import type { QueryClient } from '@tanstack/svelte-query'
5+
import type { PersistQueryClientOptions } from '@tanstack/query-persist-client-core'
6+
import type { Writable } from 'svelte/store'
7+
import type { StatusResult } from '../utils'
8+
9+
export let queryClient: QueryClient
10+
export let persistOptions: Omit<PersistQueryClientOptions, 'queryClient'>
11+
export let key: Array<string>
12+
export let states: Writable<Array<StatusResult<string>>>
13+
</script>
14+
15+
<PersistQueryClientProvider client={queryClient} {persistOptions}>
16+
<InitialData {key} {states} />
17+
</PersistQueryClientProvider>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<script lang="ts">
2+
import { createQuery } from '@tanstack/svelte-query'
3+
import { get } from 'svelte/store'
4+
import { sleep } from '../utils'
5+
6+
export let key: Array<string>
7+
8+
const state = createQuery({
9+
queryKey: key,
10+
queryFn: async () => {
11+
await sleep(10)
12+
return 'fetched'
13+
},
14+
})
15+
16+
let data = get(state).data
17+
let fetchStatus = get(state).fetchStatus
18+
state.subscribe((s) => {
19+
data = s.data
20+
fetchStatus = s.fetchStatus
21+
})
22+
</script>
23+
24+
<div>
25+
<h1>{data}</h1>
26+
<h2>fetchStatus: {fetchStatus}</h2>
27+
</div>

0 commit comments

Comments
 (0)