Skip to content
Merged
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
9 changes: 9 additions & 0 deletions .changeset/solid-query-public-hydration-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@tanstack/solid-query': patch
'@tanstack/solid-query-devtools': patch
'@tanstack/solid-query-persist-client': patch
---

Move off Solid's internal `sharedConfig` onto its public hydration API. The hydrating-mount checks read `isHydrating()`, the server cache stream writes through `getHydrationWriter()` gated on `isHydratable()` (so `<NoHydration>` is still respected), and `useQuery` consumes its streamed entry with `takeHydrationValue()`. `sharedConfig` is internal in Solid 2.0 and absent from the published `solid-js` declarations, so the previous imports no longer type-check.

These APIs ship in Solid `2.0.0-rc.13`, so the `solid-js` / `@solidjs/web` peer floor is now `>=2.0.0-rc.13`.
4 changes: 2 additions & 2 deletions examples/solid/astro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
"@tanstack/solid-query": "^6.0.0-rc.4",
"@tanstack/solid-query-devtools": "^6.0.0-rc.4",
"astro": "^5.5.6",
"@solidjs/web": "^2.0.0-rc.9",
"solid-js": "^2.0.0-rc.9",
"@solidjs/web": "^2.0.0-rc.13",
"solid-js": "^2.0.0-rc.13",
"tailwindcss": "^3.4.7",
"typescript": "5.8.3"
}
Expand Down
6 changes: 3 additions & 3 deletions examples/solid/basic-graphql-request/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
"@tanstack/solid-query-devtools": "^6.0.0-rc.4",
"graphql": "^16.9.0",
"graphql-request": "^7.1.2",
"@solidjs/web": "^2.0.0-rc.9",
"solid-js": "^2.0.0-rc.9"
"@solidjs/web": "^2.0.0-rc.13",
"solid-js": "^2.0.0-rc.13"
},
"devDependencies": {
"@solidjs/vite-plugin": "^3.0.0-next.44",
"@solidjs/vite-plugin": "^3.0.0-next.46",
"typescript": "5.8.3",
"vite": "^8.3.0"
}
Expand Down
6 changes: 3 additions & 3 deletions examples/solid/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
"dependencies": {
"@tanstack/solid-query": "^6.0.0-rc.4",
"@tanstack/solid-query-devtools": "^6.0.0-rc.4",
"@solidjs/web": "^2.0.0-rc.9",
"solid-js": "^2.0.0-rc.9"
"@solidjs/web": "^2.0.0-rc.13",
"solid-js": "^2.0.0-rc.13"
},
"devDependencies": {
"@solidjs/vite-plugin": "^3.0.0-next.44",
"@solidjs/vite-plugin": "^3.0.0-next.46",
"typescript": "5.8.3",
"vite": "^8.3.0"
}
Expand Down
6 changes: 3 additions & 3 deletions examples/solid/default-query-function/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
"dependencies": {
"@tanstack/solid-query": "^6.0.0-rc.4",
"@tanstack/solid-query-devtools": "^6.0.0-rc.4",
"@solidjs/web": "^2.0.0-rc.9",
"solid-js": "^2.0.0-rc.9"
"@solidjs/web": "^2.0.0-rc.13",
"solid-js": "^2.0.0-rc.13"
},
"devDependencies": {
"@solidjs/vite-plugin": "^3.0.0-next.44",
"@solidjs/vite-plugin": "^3.0.0-next.46",
"typescript": "5.8.3",
"vite": "^8.3.0"
}
Expand Down
6 changes: 3 additions & 3 deletions examples/solid/offline/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
"@tanstack/solid-query-devtools": "^6.0.0-rc.4",
"@tanstack/solid-query-persist-client": "^6.0.0-rc.4",
"msw": "^2.6.6",
"@solidjs/web": "^2.0.0-rc.9",
"solid-js": "^2.0.0-rc.9"
"@solidjs/web": "^2.0.0-rc.13",
"solid-js": "^2.0.0-rc.13"
},
"devDependencies": {
"@solidjs/vite-plugin": "^3.0.0-next.44",
"@solidjs/vite-plugin": "^3.0.0-next.46",
"typescript": "5.8.3",
"vite": "^8.3.0"
},
Expand Down
6 changes: 3 additions & 3 deletions examples/solid/simple/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
"dependencies": {
"@tanstack/solid-query": "^6.0.0-rc.4",
"@tanstack/solid-query-devtools": "^6.0.0-rc.4",
"@solidjs/web": "^2.0.0-rc.9",
"solid-js": "^2.0.0-rc.9"
"@solidjs/web": "^2.0.0-rc.13",
"solid-js": "^2.0.0-rc.13"
},
"devDependencies": {
"@solidjs/vite-plugin": "^3.0.0-next.44",
"@solidjs/vite-plugin": "^3.0.0-next.46",
"@tanstack/eslint-plugin-query": "^5.101.4",
"typescript": "5.8.3",
"vite": "^8.3.0"
Expand Down
4 changes: 2 additions & 2 deletions examples/solid/solid-start-streaming/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
"@solidjs/start": "^1.1.3",
"@tanstack/solid-query": "^6.0.0-rc.4",
"@tanstack/solid-query-devtools": "^6.0.0-rc.4",
"@solidjs/web": "^2.0.0-rc.9",
"solid-js": "^2.0.0-rc.9",
"@solidjs/web": "^2.0.0-rc.13",
"solid-js": "^2.0.0-rc.13",
"vinxi": "^0.5.3"
},
"engines": {
Expand Down
6 changes: 3 additions & 3 deletions integrations/solid-vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
"dependencies": {
"@tanstack/solid-query": "workspace:*",
"@tanstack/solid-query-devtools": "workspace:*",
"solid-js": "^2.0.0-rc.9",
"solid-js": "^2.0.0-rc.13",
"vite": "^8.3.0",
"@solidjs/web": "^2.0.0-rc.9",
"@solidjs/vite-plugin": "^3.0.0-next.44"
"@solidjs/web": "^2.0.0-rc.13",
"@solidjs/vite-plugin": "^3.0.0-next.46"
}
}
12 changes: 6 additions & 6 deletions packages/solid-query-devtools/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,21 +67,21 @@
"devDependencies": {
"@babel/core": "^7.28.0",
"@babel/preset-typescript": "^7.18.6",
"@solidjs/babel-plugin": "^2.0.0-rc.9",
"@solidjs/signals": "^2.0.0-rc.9",
"@solidjs/babel-plugin": "^2.0.0-rc.13",
"@solidjs/signals": "^2.0.0-rc.13",
"@solidjs/testing-library": "^0.8.10",
"@solidjs/vite-plugin": "^3.0.0-next.44",
"@solidjs/web": "^2.0.0-rc.9",
"@solidjs/vite-plugin": "^3.0.0-next.46",
"@solidjs/web": "^2.0.0-rc.13",
"@tanstack/solid-query": "workspace:*",
"@vitest/coverage-istanbul": "4.0.6",
"npm-run-all2": "^5.0.0",
"solid-js": "^2.0.0-rc.9",
"solid-js": "^2.0.0-rc.13",
"tsup-preset-solid": "^2.2.0",
"vite": "^8.3.0",
"vitest": "^4.0.18"
},
"peerDependencies": {
"@tanstack/solid-query": "workspace:^",
"solid-js": ">=2.0.0-rc.9 <3.0.0"
"solid-js": ">=2.0.0-rc.13 <3.0.0"
}
}
6 changes: 3 additions & 3 deletions packages/solid-query-devtools/src/clientOnly.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {
createMemo,
createSignal,
isHydrating,
omit,
onSettled,
sharedConfig,
untrack,
} from 'solid-js'
import { isServer } from '@solidjs/web'
Expand All @@ -30,8 +30,8 @@ export default function clientOnly<T extends Component<any>>(
let Comp: T | undefined
let m: boolean
const rest = omit(props, 'fallback')
if ((Comp = comp()) && !sharedConfig.hydrating) return Comp(rest)
const [mounted, setMounted] = createSignal(!sharedConfig.hydrating)
if ((Comp = comp()) && !isHydrating()) return Comp(rest)
const [mounted, setMounted] = createSignal(!isHydrating())
onSettled(() => {
setMounted(true)
})
Expand Down
10 changes: 5 additions & 5 deletions packages/solid-query-persist-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,21 +68,21 @@
"devDependencies": {
"@babel/core": "^7.28.0",
"@babel/preset-typescript": "^7.18.6",
"@solidjs/babel-plugin": "^2.0.0-rc.9",
"@solidjs/babel-plugin": "^2.0.0-rc.13",
"@solidjs/testing-library": "^0.8.10",
"@solidjs/vite-plugin": "^3.0.0-next.44",
"@solidjs/web": "^2.0.0-rc.9",
"@solidjs/vite-plugin": "^3.0.0-next.46",
"@solidjs/web": "^2.0.0-rc.13",
"@tanstack/query-test-utils": "workspace:*",
"@tanstack/solid-query": "workspace:*",
"@vitest/coverage-istanbul": "4.0.6",
"npm-run-all2": "^5.0.0",
"solid-js": "^2.0.0-rc.9",
"solid-js": "^2.0.0-rc.13",
"tsup-preset-solid": "^2.2.0",
"vite": "^8.3.0",
"vitest": "^4.0.18"
},
"peerDependencies": {
"@tanstack/solid-query": "workspace:^",
"solid-js": ">=2.0.0-rc.9 <3.0.0"
"solid-js": ">=2.0.0-rc.13 <3.0.0"
}
}
12 changes: 6 additions & 6 deletions packages/solid-query/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,20 +70,20 @@
"devDependencies": {
"@babel/core": "^7.28.0",
"@babel/preset-typescript": "^7.18.6",
"@solidjs/babel-plugin": "^2.0.0-rc.9",
"@solidjs/babel-plugin": "^2.0.0-rc.13",
"@solidjs/testing-library": "^0.8.10",
"@solidjs/vite-plugin": "^3.0.0-next.44",
"@solidjs/web": "^2.0.0-rc.9",
"@solidjs/vite-plugin": "^3.0.0-next.46",
"@solidjs/web": "^2.0.0-rc.13",
"@tanstack/query-test-utils": "workspace:*",
"@vitest/coverage-istanbul": "4.0.6",
"npm-run-all2": "^5.0.0",
"solid-js": "^2.0.0-rc.9",
"solid-js": "^2.0.0-rc.13",
"tsup-preset-solid": "^2.2.0",
"vite": "^8.3.0",
"vitest": "^4.0.18"
},
"peerDependencies": {
"@solidjs/web": ">=2.0.0-rc.9 <3.0.0",
"solid-js": ">=2.0.0-rc.9 <3.0.0"
"@solidjs/web": ">=2.0.0-rc.13 <3.0.0",
"solid-js": ">=2.0.0-rc.13 <3.0.0"
}
}
20 changes: 6 additions & 14 deletions packages/solid-query/src/QueryClientProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createContext, onCleanup, sharedConfig, useContext } from 'solid-js'
import { REVALIDATE_HEADER } from '@solidjs/web'
import { createContext, isHydratable, onCleanup, useContext } from 'solid-js'
import { REVALIDATE_HEADER, getHydrationWriter } from '@solidjs/web'
import { hydrate } from '@tanstack/query-core'
import { subscribeFlightData } from '@solidjs/web/server-functions'
import type { DehydratedState, Query } from '@tanstack/query-core'
Expand Down Expand Up @@ -148,16 +148,8 @@ export type QueryClientProviderProps = {
* serialize, so seroval's cross-reference dedupe emits it once.
*/
function serializeCacheOnServer(client: QueryClient): void {
const ctx = (
sharedConfig as unknown as {
context?: {
async?: boolean
noHydrate?: boolean
serialize: (key: string, value: unknown) => void
}
}
).context
if (!ctx || !ctx.async || ctx.noHydrate) return
const writer = getHydrationWriter()
if (!writer || !writer.async || !isHydratable()) return

const cache = client.getQueryCache()
// The standard dehydrate filter gates the wire here too, so apps keep
Expand All @@ -175,7 +167,7 @@ function serializeCacheOnServer(client: QueryClient): void {
const state = query.state
if (state.status === 'success') {
seen.add(query.queryHash)
ctx.serialize(HYDRATION_KEY_PREFIX + query.queryHash, {
writer.write(HYDRATION_KEY_PREFIX + query.queryHash, {
data: state.data,
t: state.dataUpdatedAt,
})
Expand All @@ -185,7 +177,7 @@ function serializeCacheOnServer(client: QueryClient): void {
const promise = query.promise as Promise<unknown> | undefined
if (!promise) return
seen.add(query.queryHash)
ctx.serialize(
writer.write(
HYDRATION_KEY_PREFIX + query.queryHash,
promise.then(() => ({
data: query.state.data,
Expand Down
54 changes: 27 additions & 27 deletions packages/solid-query/src/__tests__/hydration.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -507,14 +507,14 @@ describe('streaming SSR hydration', () => {
}
})

// The data node has default ('server') hydration semantics: the
// serialized server value owns the DOM for the whole hydration window,
// and a latched node that recomputes mid-stream (a cache write landed)
// arms the engine's hydration-end takeover — the change commits when the
// stream closes, deferred rather than lost. Network activity is NOT
// deferred: observers attach per-query as the channel primes, so
// mid-stream invalidations refetch immediately.
it('cache writes during the open stream commit when hydration completes', async () => {
// Hydration does not wait for the page: once the root pass is over, a
// node outside every still-pending streamed boundary answers client
// writes. The header's boundary has resumed, so a cache write while the
// feed keeps the stream open reaches its DOM immediately, and so does a
// mid-stream refetch (observers attach per-query as the channel primes).
// The pending feed boundary is untouched and hydrates from the server
// payload when its chunk lands.
it('cache writes during the open stream commit immediately outside pending boundaries', async () => {
const { phase1, phase2 } = splitStream()
const app = bundle.createStreamApp()
const container = document.createElement('div')
Expand All @@ -533,39 +533,39 @@ describe('streaming SSR hydration', () => {
// The slow section still shows its fallback.
expect(container.querySelector('#feed')).toBeNull()

// A write while the stream is open reaches the CACHE immediately but
// not the DOM — the serialized server value holds the document.
// A write while the stream is open reaches the cache and the
// resumed header's DOM at once.
app.queryClient.setQueryData(['header'], 'updated-client')
await tick(30)
await vi.waitFor(() => {
expect(container.querySelector('#header')?.textContent).toBe(
'updated-client',
)
})
expect(app.queryClient.getQueryData(['header'])).toBe('updated-client')
expect(container.querySelector('#header')?.textContent).toBe(
'header-server',
)
expect(container.querySelector('#feed')).toBeNull()

// An invalidation while the stream is open refetches immediately
// (the observer is subscribed — network is not deferred), but the
// result is held with the rest.
// (the observer is subscribed) and its result commits as it lands.
void app.queryClient.invalidateQueries({ queryKey: ['header'] })
await vi.waitFor(() => {
expect(app.counts.header).toBe(1)
expect(container.querySelector('#header')?.textContent).toBe(
'header-client',
)
})
expect(container.querySelector('#header')?.textContent).toBe(
'header-server',
)
expect(app.counts.header).toBe(1)
expect(container.querySelector('#feed')).toBeNull()

// The late boundary hydrates, closing the stream — the divergence
// takeover re-runs the latched node and the held state commits.
// The late boundary hydrates from the server payload, closing the
// stream; the header keeps its client state.
applyChunks(container, phase2)
await vi.waitFor(() => {
expect(container.querySelector('#feed')?.textContent).toBe(
'feed-server',
)
})
await vi.waitFor(() => {
expect(container.querySelector('#header')?.textContent).toBe(
'header-client',
)
})
expect(container.querySelector('#header')?.textContent).toBe(
'header-client',
)
expect(app.counts.feed).toBe(0)

// And fully live from then on.
Expand Down
5 changes: 2 additions & 3 deletions packages/solid-query/src/cacheAggregate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import {
createEffect,
createOptimistic,
createSignal,
isHydrating,
onCleanup,
sharedConfig,
untrack,
} from 'solid-js'
import type { Accessor } from 'solid-js'
Expand Down Expand Up @@ -47,8 +47,7 @@ export function createCacheAggregate<T>(
read: (prev: T) => T,
empty: T,
): Accessor<T> {
const hydratedMount =
!isServer && (sharedConfig as { hydrating?: boolean }).hydrating === true
const hydratedMount = isHydrating()

// Cast: createSignal's value overload excludes functions (a function
// argument means a compute); aggregate values are counts and arrays.
Expand Down
Loading
Loading