Skip to content

Commit 28fc443

Browse files
fix(solid-query): don't hang async SSR when a disabled query is rendered
1 parent feb1efd commit 28fc443

3 files changed

Lines changed: 54 additions & 0 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tanstack/solid-query': patch
3+
---
4+
5+
Fix `renderToStringAsync` hanging during SSR when a query is disabled: strip the unserializable `experimental_prefetchInRender` promise from the hydratable observer result, since a disabled query's promise never settles and the SSR serializer would await it forever.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { describe, expect, it, vi } from 'vitest'
2+
import { render, waitFor } from '@solidjs/testing-library'
3+
import { QueryClient, QueryClientProvider, useQuery } from '..'
4+
import type * as SolidWeb from 'solid-js/web'
5+
import type { UseQueryResult } from '..'
6+
7+
// Force the server code path: on the server `useBaseQuery` enables
8+
// `experimental_prefetchInRender` and resolves the resource with a
9+
// serializable `hydratableObserverResult()`.
10+
vi.mock('solid-js/web', async (importOriginal) => {
11+
const mod = await importOriginal<typeof SolidWeb>()
12+
return { ...mod, isServer: true }
13+
})
14+
15+
describe('useQuery on the server', () => {
16+
it('resolves a disabled query without leaking the prefetch promise (#10907)', async () => {
17+
const client = new QueryClient()
18+
let state: UseQueryResult<string> | undefined
19+
20+
function Page() {
21+
const query = useQuery(() => ({
22+
queryKey: ['disabled-ssr'],
23+
queryFn: () => Promise.resolve('data'),
24+
enabled: false,
25+
}))
26+
state = query
27+
return <div>data: {String(query.data)}</div>
28+
}
29+
30+
const rendered = render(() => (
31+
<QueryClientProvider client={client}>
32+
<Page />
33+
</QueryClientProvider>
34+
))
35+
36+
await waitFor(() => rendered.getByText('data: undefined'))
37+
38+
// The resolved result is serialized into the SSR payload, so it must not
39+
// carry functions or promises. The `experimental_prefetchInRender`
40+
// promise of a disabled query never settles, which would hang
41+
// `renderToStringAsync` while the serializer awaits it.
42+
expect(state!.refetch).toBeUndefined()
43+
expect(state!.promise).toBeUndefined()
44+
})
45+
})

packages/solid-query/src/useBaseQuery.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ const hydratableObserverResult = <
7979
// During SSR, functions cannot be serialized, so we need to remove them
8080
// This is safe because we will add these functions back when the query is hydrated
8181
refetch: undefined,
82+
// The `experimental_prefetchInRender` promise cannot be serialized either.
83+
// For a disabled query it never settles, which would hang stream/async
84+
// SSR while the serializer awaits it (#10907).
85+
promise: undefined,
8286
}
8387

8488
// If the query is an infinite query, we need to remove additional properties

0 commit comments

Comments
 (0)