Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
5 changes: 5 additions & 0 deletions .changeset/rotten-bars-sit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/solid-router': patch
---

Fix streaming when using Await component
21 changes: 21 additions & 0 deletions e2e/solid-start/basic/src/routeTree.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { Route as ScriptsRouteImport } from './routes/scripts'
import { Route as RawStreamRouteImport } from './routes/raw-stream'
import { Route as PostsRouteImport } from './routes/posts'
import { Route as LinksRouteImport } from './routes/links'
import { Route as Issue6715RouteImport } from './routes/issue-6715'
import { Route as InlineScriptsRouteImport } from './routes/inline-scripts'
import { Route as DeferredRouteImport } from './routes/deferred'
import { Route as LayoutRouteImport } from './routes/_layout'
Expand Down Expand Up @@ -99,6 +100,11 @@ const LinksRoute = LinksRouteImport.update({
path: '/links',
getParentRoute: () => rootRouteImport,
} as any)
const Issue6715Route = Issue6715RouteImport.update({
id: '/issue-6715',
path: '/issue-6715',
getParentRoute: () => rootRouteImport,
} as any)
const InlineScriptsRoute = InlineScriptsRouteImport.update({
id: '/inline-scripts',
path: '/inline-scripts',
Expand Down Expand Up @@ -387,6 +393,7 @@ export interface FileRoutesByFullPath {
'/specialChars': typeof SpecialCharsRouteRouteWithChildren
'/deferred': typeof DeferredRoute
'/inline-scripts': typeof InlineScriptsRoute
'/issue-6715': typeof Issue6715Route
'/links': typeof LinksRoute
'/posts': typeof PostsRouteWithChildren
'/raw-stream': typeof RawStreamRouteWithChildren
Expand Down Expand Up @@ -444,6 +451,7 @@ export interface FileRoutesByTo {
'/specialChars': typeof SpecialCharsRouteRouteWithChildren
'/deferred': typeof DeferredRoute
'/inline-scripts': typeof InlineScriptsRoute
'/issue-6715': typeof Issue6715Route
'/links': typeof LinksRoute
'/scripts': typeof ScriptsRoute
'/stream': typeof StreamRoute
Expand Down Expand Up @@ -501,6 +509,7 @@ export interface FileRoutesById {
'/_layout': typeof LayoutRouteWithChildren
'/deferred': typeof DeferredRoute
'/inline-scripts': typeof InlineScriptsRoute
'/issue-6715': typeof Issue6715Route
'/links': typeof LinksRoute
'/posts': typeof PostsRouteWithChildren
'/raw-stream': typeof RawStreamRouteWithChildren
Expand Down Expand Up @@ -563,6 +572,7 @@ export interface FileRouteTypes {
| '/specialChars'
| '/deferred'
| '/inline-scripts'
| '/issue-6715'
| '/links'
| '/posts'
| '/raw-stream'
Expand Down Expand Up @@ -620,6 +630,7 @@ export interface FileRouteTypes {
| '/specialChars'
| '/deferred'
| '/inline-scripts'
| '/issue-6715'
| '/links'
| '/scripts'
| '/stream'
Expand Down Expand Up @@ -676,6 +687,7 @@ export interface FileRouteTypes {
| '/_layout'
| '/deferred'
| '/inline-scripts'
| '/issue-6715'
| '/links'
| '/posts'
| '/raw-stream'
Expand Down Expand Up @@ -738,6 +750,7 @@ export interface RootRouteChildren {
LayoutRoute: typeof LayoutRouteWithChildren
DeferredRoute: typeof DeferredRoute
InlineScriptsRoute: typeof InlineScriptsRoute
Issue6715Route: typeof Issue6715Route
LinksRoute: typeof LinksRoute
PostsRoute: typeof PostsRouteWithChildren
RawStreamRoute: typeof RawStreamRouteWithChildren
Expand Down Expand Up @@ -798,6 +811,13 @@ declare module '@tanstack/solid-router' {
preLoaderRoute: typeof LinksRouteImport
parentRoute: typeof rootRouteImport
}
'/issue-6715': {
id: '/issue-6715'
path: '/issue-6715'
fullPath: '/issue-6715'
preLoaderRoute: typeof Issue6715RouteImport
parentRoute: typeof rootRouteImport
}
'/inline-scripts': {
id: '/inline-scripts'
path: '/inline-scripts'
Expand Down Expand Up @@ -1378,6 +1398,7 @@ const rootRouteChildren: RootRouteChildren = {
LayoutRoute: LayoutRouteWithChildren,
DeferredRoute: DeferredRoute,
InlineScriptsRoute: InlineScriptsRoute,
Issue6715Route: Issue6715Route,
LinksRoute: LinksRoute,
PostsRoute: PostsRouteWithChildren,
RawStreamRoute: RawStreamRouteWithChildren,
Expand Down
29 changes: 29 additions & 0 deletions e2e/solid-start/basic/src/routes/issue-6715.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Await, createFileRoute } from '@tanstack/solid-router'
import { createServerFn } from '@tanstack/solid-start'

const promise = createServerFn().handler(async () => {
await new Promise((r) => setTimeout(r, 3000))
return crypto.randomUUID()
})

export const Route = createFileRoute('/issue-6715')({
component: RouteComponent,
loader() {
return { promise: promise() }
},
})

function RouteComponent() {
const data = Route.useLoaderData()
return (
<>
data{' '}
<Await
fallback={<p data-testid="issue-6715-loading">Loading...</p>}
promise={data().promise}
>
{(data) => <span data-testid="issue-6715-data">{data}</span>}
</Await>
</>
)
}
12 changes: 12 additions & 0 deletions e2e/solid-start/basic/tests/streaming.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,15 @@ test('streaming loader data', async ({ page }) => {
await expect(page.getByTestId('promise-data')).toContainText('promise-data')
await expect(page.getByTestId('stream-data')).toContainText('stream-data')
})

test('streams Await fallback for server function loader promises', async ({
page,
}) => {
const response = await page.request.get('/issue-6715')
const html = await response.text()

expect(html).toContain('data-testid="issue-6715-loading"')

await page.goto('/issue-6715')
await expect(page.getByTestId('issue-6715-data')).not.toBeEmpty()
})
39 changes: 30 additions & 9 deletions packages/solid-router/src/awaited.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,40 @@ export function Await<T>(
fallback?: SolidNode
children: (result: T) => SolidNode
},
) {
if (!('fallback' in props)) {
Comment thread
coderabbitai[bot] marked this conversation as resolved.
const [resource] = Solid.createResource(
() => defer(props.promise),
(p) => p,
{
deferStream: true,
},
)

return (
<Solid.Show when={resource()}>
{(data) => props.children(data())}
</Solid.Show>
)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

return (
<Solid.Suspense fallback={props.fallback}>
<AwaitInner {...props} />
</Solid.Suspense>
)
}

function AwaitInner<T>(
props: AwaitOptions<T> & {
fallback?: SolidNode
children: (result: T) => SolidNode
},
) {
const [resource] = Solid.createResource(
() => defer(props.promise),
// Simple passthrough - just return the promise for Solid to await
(p) => p,
{
deferStream: true,
},
)

return (
<Solid.Show fallback={props.fallback} when={resource()}>
{(data) => props.children(data())}
</Solid.Show>
)
return props.children(resource() as T)
}
Loading