Skip to content
Closed
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
16 changes: 16 additions & 0 deletions e2e/solid-start/basic-test-suite/src/streaming.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,22 @@ test('Directly visiting the deferred route', async ({ page }) => {
)
})

test('deferred route streams boundaries independently', async ({ page }) => {
await page.goto('/deferred', { waitUntil: 'commit' })

await expect(page.getByTestId('regular-person')).toContainText('John Doe')
await expect(page.getByText('Loading person...')).toBeVisible()
await expect(page.getByText('Loading stuff...')).toBeVisible()

await expect(page.getByTestId('deferred-person')).toContainText(
'Tanner Linsley',
)
await expect(page.getByText('Loading stuff...')).toBeVisible()
await expect(page.getByTestId('deferred-stuff')).toContainText(
'Hello deferred!',
)
})

test('streaming loader data', async ({ page }) => {
await page.goto('/stream')

Expand Down
14 changes: 10 additions & 4 deletions packages/router-core/src/ssr/transformStreamWithRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,9 @@ export function transformStreamWithRouter(
// between-chunk text buffer; keep bounded to avoid unbounded memory
let leftover = ''

// captured closing tags from </body> onward
// Captured closing tags that must stay after router-injected scripts.
// Some renderers, like Solid, continue streaming boundary chunks after
// </html>; those chunks should still pass through before these tags.
let pendingClosingTags = ''

// conservative cap: enough to hold any partial closing tag + a bit
Expand Down Expand Up @@ -404,9 +406,11 @@ export function transformStreamWithRouter(
}
}

// If we already saw </body>, everything else is part of tail; buffer it.
// If we already saw </body>, keep streaming app chunks before the
// captured closing tags instead of buffering them until render end.
if (pendingClosingTags) {
pendingClosingTags += chunkString
flushPendingRouterHtml()
safeEnqueue(chunkString)
leftover = ''
continue
}
Expand All @@ -419,9 +423,11 @@ export function transformStreamWithRouter(
htmlEndIndex !== -1 &&
bodyEndIndex < htmlEndIndex
) {
pendingClosingTags = chunkString.slice(bodyEndIndex)
const htmlEndTagEnd = htmlEndIndex + HTML_END_TAG.length
pendingClosingTags = chunkString.slice(bodyEndIndex, htmlEndTagEnd)
safeEnqueue(chunkString.slice(0, bodyEndIndex))
flushPendingRouterHtml()
safeEnqueue(chunkString.slice(htmlEndTagEnd))
leftover = ''
continue
}
Expand Down
Loading