-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Add preact persist plugin #10120
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
base: main
Are you sure you want to change the base?
Add preact persist plugin #10120
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| id: createAsyncStoragePersister | ||
| title: createAsyncStoragePersister | ||
| ref: docs/framework/react/plugins/createAsyncStoragePersister.md | ||
| replace: { 'react-query': 'preact-query' } | ||
| --- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| id: createPersister | ||
| title: experimental_createPersister | ||
| ref: docs/framework/react/plugins/createPersister.md | ||
| replace: { 'react-query': 'preact-query' } | ||
| --- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| id: createSyncStoragePersister | ||
| title: createSyncStoragePersister | ||
| ref: docs/framework/react/plugins/createSyncStoragePersister.md | ||
| replace: { 'react-query': 'preact-query' } | ||
| --- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| // @ts-check | ||
| // @ts-ignore: no types for eslint-config-preact | ||
| import preact from 'eslint-config-preact' | ||
| // eslint-config-preact uses typescript-eslint under the hood | ||
| import tseslint from 'typescript-eslint' | ||
|
|
||
| import rootConfig from './root.eslint.config.js' | ||
|
|
||
| export default [ | ||
| ...rootConfig, | ||
| ...preact, | ||
| { | ||
| files: ['**/*.{ts,tsx}'], | ||
| languageOptions: { | ||
| parser: tseslint.parser, | ||
| parserOptions: { | ||
| project: true, | ||
| }, | ||
| }, | ||
| plugins: { | ||
| 'typescript-eslint': tseslint.plugin, | ||
| }, | ||
| rules: { | ||
| // Disable base rule to prevent overload false positives | ||
| 'no-redeclare': 'off', | ||
| 'no-duplicate-imports': 'off', | ||
| 'no-unused-vars': 'off', | ||
| 'import/order': 'off', | ||
| 'sort-imports': 'off', | ||
| 'no-import-assign': 'off', | ||
| // TS-aware version handles overloads correctly | ||
| '@typescript-eslint/no-redeclare': 'error', | ||
| '@typescript-eslint/array-type': 'off', | ||
| '@typescript-eslint/no-unnecessary-type-assertion': 'off', | ||
| '@typescript-eslint/no-unnecessary-condition': 'off', | ||
| }, | ||
| }, | ||
| ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| { | ||
| "name": "@tanstack/preact-query-persist-client", | ||
| "version": "5.91.0", | ||
| "description": "Preact bindings to work with persisters in TanStack/preact-query", | ||
| "author": "tannerlinsley", | ||
| "license": "MIT", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "git+https://github.com/TanStack/query.git", | ||
| "directory": "packages/preact-query-persist-client" | ||
| }, | ||
| "homepage": "https://tanstack.com/query", | ||
| "funding": { | ||
| "type": "github", | ||
| "url": "https://github.com/sponsors/tannerlinsley" | ||
| }, | ||
| "scripts": { | ||
| "clean": "premove ./build ./coverage ./dist-ts", | ||
| "compile": "tsc --build", | ||
| "test:eslint": "eslint --concurrency=auto ./src", | ||
| "test:types": "npm-run-all --serial test:types:*", | ||
| "test:types:ts50": "node ../../node_modules/typescript50/lib/tsc.js --build tsconfig.legacy.json", | ||
| "test:types:ts51": "node ../../node_modules/typescript51/lib/tsc.js --build tsconfig.legacy.json", | ||
| "test:types:ts52": "node ../../node_modules/typescript52/lib/tsc.js --build tsconfig.legacy.json", | ||
| "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js --build tsconfig.legacy.json", | ||
| "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js --build tsconfig.legacy.json", | ||
| "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js --build tsconfig.legacy.json", | ||
| "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js --build tsconfig.legacy.json", | ||
| "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js --build tsconfig.legacy.json", | ||
| "test:types:tscurrent": "tsc --build", | ||
| "test:lib": "vitest --retry=3", | ||
| "test:lib:dev": "pnpm run test:lib --watch", | ||
| "test:build": "publint --strict && attw --pack", | ||
| "build": "tsup --tsconfig tsconfig.prod.json" | ||
| }, | ||
| "type": "module", | ||
| "types": "build/legacy/index.d.ts", | ||
| "main": "build/legacy/index.cjs", | ||
| "module": "build/legacy/index.js", | ||
| "exports": { | ||
| ".": { | ||
| "@tanstack/custom-condition": "./src/index.ts", | ||
| "import": { | ||
| "types": "./build/modern/index.d.ts", | ||
| "default": "./build/modern/index.js" | ||
| }, | ||
| "require": { | ||
| "types": "./build/modern/index.d.cts", | ||
| "default": "./build/modern/index.cjs" | ||
| } | ||
| }, | ||
| "./package.json": "./package.json" | ||
| }, | ||
| "sideEffects": false, | ||
| "files": [ | ||
| "build", | ||
| "src", | ||
| "!src/__tests__" | ||
| ], | ||
| "dependencies": { | ||
| "@tanstack/query-persist-client-core": "workspace:*" | ||
| }, | ||
| "devDependencies": { | ||
| "@preact/preset-vite": "^2.10.2", | ||
| "@tanstack/preact-query": "workspace:*", | ||
| "@tanstack/query-test-utils": "workspace:*", | ||
| "@testing-library/preact": "^3.2.4", | ||
| "eslint-config-preact": "^2.0.0", | ||
| "npm-run-all2": "^5.0.0", | ||
| "preact": "^10.28.0", | ||
| "typescript-eslint": "^8.54.0" | ||
| }, | ||
| "peerDependencies": { | ||
| "@tanstack/preact-query": "workspace:^", | ||
| "preact": "^10.0.0" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../eslint.config.js |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../scripts/getTsupConfig.js |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| import { useEffect, useRef, useState } from 'preact/hooks' | ||
| import type { VNode } from 'preact' | ||
|
|
||
| import { | ||
| persistQueryClientRestore, | ||
| persistQueryClientSubscribe, | ||
| } from '@tanstack/query-persist-client-core' | ||
| import { IsRestoringProvider, QueryClientProvider } from '@tanstack/preact-query' | ||
| import type { PersistQueryClientOptions } from '@tanstack/query-persist-client-core' | ||
| import type { OmitKeyof, QueryClientProviderProps } from '@tanstack/preact-query' | ||
|
|
||
| export type PersistQueryClientProviderProps = QueryClientProviderProps & { | ||
| persistOptions: OmitKeyof<PersistQueryClientOptions, 'queryClient'> | ||
| onSuccess?: () => Promise<unknown> | unknown | ||
| onError?: () => Promise<unknown> | unknown | ||
| } | ||
|
|
||
| export const PersistQueryClientProvider = ({ | ||
| children, | ||
| persistOptions, | ||
| onSuccess, | ||
| onError, | ||
| ...props | ||
| }: PersistQueryClientProviderProps): VNode => { | ||
| const [isRestoring, setIsRestoring] = useState(true) | ||
| const refs = useRef({ persistOptions, onSuccess, onError }) | ||
| const didRestore = useRef(false) | ||
|
|
||
| useEffect(() => { | ||
| refs.current = { persistOptions, onSuccess, onError } | ||
| }) | ||
|
|
||
| useEffect(() => { | ||
| const options = { | ||
| ...refs.current.persistOptions, | ||
| queryClient: props.client, | ||
| } | ||
| if (!didRestore.current) { | ||
| didRestore.current = true | ||
| persistQueryClientRestore(options) | ||
| .then(() => refs.current.onSuccess?.()) | ||
| .catch(() => refs.current.onError?.()) | ||
| .finally(() => { | ||
| setIsRestoring(false) | ||
| }) | ||
| } | ||
| return isRestoring ? undefined : persistQueryClientSubscribe(options) | ||
| }, [props.client, isRestoring]) | ||
|
Comment on lines
+33
to
+48
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cd . && find . -type f -name "*PersistQueryClientProvider*" | head -20Repository: TanStack/query Length of output: 617 🏁 Script executed: ls -la packages/Repository: TanStack/query Length of output: 1931 🏁 Script executed: find . -name "PersistQueryClientProvider.tsx" -type fRepository: TanStack/query Length of output: 277 🏁 Script executed: git ls-files | grep "PersistQueryClientProvider"Repository: TanStack/query Length of output: 603 🏁 Script executed: git ls-files "**/*PersistQueryClientProvider*"Repository: TanStack/query Length of output: 603 🏁 Script executed: find packages -type f -name "*.tsx" | grep -i providerRepository: TanStack/query Length of output: 855 🏁 Script executed: find . -type f -name "*.tsx" -o -name "*.ts" | xargs grep -l "PersistQueryClientProvider" 2>/dev/nullRepository: TanStack/query Length of output: 953 🏁 Script executed: tree -L 3 -d 2>/dev/null || find . -maxdepth 3 -type d | head -30Repository: TanStack/query Length of output: 6546 🏁 Script executed: pwd && ls -laRepository: TanStack/query Length of output: 2437 🏁 Script executed: find . -path "*/preact-query-persist-client/*" -type fRepository: TanStack/query Length of output: 623 🏁 Script executed: rg "didRestore.current" -t tsx -t tsRepository: TanStack/query Length of output: 85 🏁 Script executed: git ls-files | wc -l && git ls-files | grep -i providerRepository: TanStack/query Length of output: 2578 🏁 Script executed: git ls-files | grep "\.tsx$"Repository: TanStack/query Length of output: 17194 🏁 Script executed: git log --oneline --all | head -5Repository: TanStack/query Length of output: 340 🏁 Script executed: git ls-files --full-name | sortRepository: TanStack/query Length of output: 50371 🏁 Script executed: git ls-files --full-name | grep -i persistRepository: TanStack/query Length of output: 9283 🏁 Script executed: find . -type f -name "*.tsx" | wc -lRepository: TanStack/query Length of output: 61 🏁 Script executed: rg "useEffect" --type tsx --type ts | grep -i "persistquery\|restore" -A 5Repository: TanStack/query Length of output: 85 🏁 Script executed: rg "persistQueryClientRestore"Repository: TanStack/query Length of output: 2830 🏁 Script executed: git ls-files | head -100Repository: TanStack/query Length of output: 4804 🏁 Script executed: cat /dev/null && pwdRepository: TanStack/query Length of output: 76 🏁 Script executed: git remote -v 2>/dev/null || echo "No git remote found"Repository: TanStack/query Length of output: 174 🏁 Script executed: git rev-parse --show-toplevel 2>/dev/null || echo "Not a git repo"Repository: TanStack/query Length of output: 76 🏁 Script executed: test -f packages/preact-query-persist-client/src/PersistQueryClientProvider.tsx && echo "File exists" || echo "File not found"Repository: TanStack/query Length of output: 69 🏁 Script executed: find . -iname "*react*query*persist*" -o -iname "*preact*query*persist*" 2>/dev/nullRepository: TanStack/query Length of output: 134 🌐 Web query:
💡 Result: In TanStack Query (v5), restoration/persistence works like this:
What happens on unmount/remount?
Manual pattern (if you’re not using
|
||
|
|
||
| return ( | ||
| <QueryClientProvider {...props}> | ||
| <IsRestoringProvider value={isRestoring}>{children}</IsRestoringProvider> | ||
| </QueryClientProvider> | ||
| ) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| // Re-export core | ||
| export * from '@tanstack/query-persist-client-core' | ||
|
|
||
| export * from './PersistQueryClientProvider' |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import '@testing-library/jest-dom/vitest' | ||
| import { act, cleanup as cleanupRTL } from '@testing-library/preact' | ||
| import { afterEach } from 'vitest' | ||
| import { notifyManager } from '@tanstack/preact-query' | ||
|
|
||
| // https://testing-library.com/docs/preact-testing-library/api#cleanup | ||
| afterEach(() => { | ||
| cleanupRTL() | ||
| }) | ||
|
|
||
| // Wrap notifications with act to make sure Preact knows about Query updates | ||
| notifyManager.setNotifyFunction((fn) => { | ||
| act(fn) | ||
| }) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| { | ||
| "extends": "../../tsconfig.json", | ||
| "compilerOptions": { | ||
| "outDir": "./dist-ts", | ||
| "rootDir": ".", | ||
| "jsx": "react-jsx", | ||
| "jsxImportSource": "preact" | ||
| }, | ||
| "include": ["src", "test-setup.ts", "*.config.*", "package.json"], | ||
| "references": [ | ||
| { "path": "../query-persist-client-core" }, | ||
| { "path": "../preact-query" } | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| { | ||
| "extends": "./tsconfig.json", | ||
| "compilerOptions": { | ||
| "jsx": "react-jsx", | ||
| "jsxImportSource": "preact", | ||
| "outDir": "./dist-ts/legacy" | ||
| }, | ||
| "include": ["src"], | ||
| "exclude": ["src/__tests__"], | ||
| "references": [ | ||
| { "path": "../query-persist-client-core" }, | ||
| { "path": "../preact-query" } | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| { | ||
| "extends": "./tsconfig.json", | ||
| "compilerOptions": { | ||
| "incremental": false, | ||
| "composite": false, | ||
| "rootDir": "../../" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| import { defineConfig } from 'tsup' | ||
| import { legacyConfig, modernConfig } from './root.tsup.config.js' | ||
|
|
||
| export default defineConfig([ | ||
| modernConfig({ entry: ['src/*.ts', 'src/*.tsx'] }), | ||
| legacyConfig({ entry: ['src/*.ts', 'src/*.tsx'] }), | ||
| ]) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| import preact from '@preact/preset-vite' | ||
| import { defineConfig } from 'vitest/config' | ||
| import type { UserConfig as ViteUserConfig } from 'vite' | ||
|
|
||
| import packageJson from './package.json' | ||
|
Comment on lines
+3
to
+5
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix import order: ESLint flags this as an Proposed fix-import { defineConfig } from 'vitest/config'
-import type { UserConfig as ViteUserConfig } from 'vite'
-
-import packageJson from './package.json'
+import { defineConfig } from 'vitest/config'
+import packageJson from './package.json'
+import type { UserConfig as ViteUserConfig } from 'vite'🧰 Tools🪛 ESLint[error] 5-5: (import/order) 🤖 Prompt for AI Agents |
||
|
|
||
| export default defineConfig({ | ||
| plugins: [preact() as ViteUserConfig['plugins']], | ||
| // fix from https://github.com/vitest-dev/vitest/issues/6992#issuecomment-2509408660 | ||
| resolve: { | ||
| conditions: ['@tanstack/custom-condition'], | ||
| }, | ||
| environments: { | ||
| ssr: { | ||
| resolve: { | ||
| conditions: ['@tanstack/custom-condition'], | ||
| }, | ||
| }, | ||
| }, | ||
| test: { | ||
| name: packageJson.name, | ||
| dir: './src', | ||
| watch: false, | ||
| environment: 'jsdom', | ||
| setupFiles: ['test-setup.ts'], | ||
| coverage: { | ||
| enabled: true, | ||
| provider: 'istanbul', | ||
| include: ['src/**/*'], | ||
| exclude: ['src/__tests__/**'], | ||
| }, | ||
| typecheck: { enabled: true }, | ||
| restoreMocks: true, | ||
| }, | ||
| }) | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix import order: type import from
preactshould follow@tanstack/*imports.ESLint reports that the
preacttype import on Line 2 should occur after the@tanstack/preact-queryimport.🔧 Proposed fix
import { useEffect, useRef, useState } from 'preact/hooks' -import type { VNode } from 'preact' import { persistQueryClientRestore, persistQueryClientSubscribe, } from '@tanstack/query-persist-client-core' import { IsRestoringProvider, QueryClientProvider } from '@tanstack/preact-query' import type { PersistQueryClientOptions } from '@tanstack/query-persist-client-core' import type { OmitKeyof, QueryClientProviderProps } from '@tanstack/preact-query' +import type { VNode } from 'preact'📝 Committable suggestion
🧰 Tools
🪛 ESLint
[error] 2-2:
preacttype import should occur after import of@tanstack/preact-query(import/order)
🤖 Prompt for AI Agents