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
64 changes: 37 additions & 27 deletions packages/router-core/src/ssr/transformStreamWithRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,10 @@ export function transformStreamWithRouter(
let timeoutHandle: NodeJS.Timeout

const finalPassThrough = createPassthrough(() => {
stopListeningToInjectedHtml?.()
if (stopListeningToInjectedHtml) {
stopListeningToInjectedHtml()
stopListeningToInjectedHtml = undefined
}
clearTimeout(timeoutHandle)
})
const textDecoder = new TextDecoder()
Expand Down Expand Up @@ -134,34 +137,36 @@ export function transformStreamWithRouter(
let processingCount = 0

// Process any already-injected HTML
router.serverSsr!.injectedHtml.forEach((promise) => {
handleInjectedHtml(promise)
})
handleInjectedHtml()

// Listen for any new injected HTML
stopListeningToInjectedHtml = router.subscribe('onInjectedHtml', (e) => {
handleInjectedHtml(e.promise)
})

function handleInjectedHtml(promise: Promise<string>) {
processingCount++

promise
.then((html) => {
if (isAppRendering) {
routerStreamBuffer += html
} else {
finalPassThrough.write(html)
}
})
.catch(injectedHtmlDonePromise.reject)
.finally(() => {
processingCount--
stopListeningToInjectedHtml = router.subscribe(
'onInjectedHtml',
handleInjectedHtml,
)

if (!isAppRendering && processingCount === 0) {
injectedHtmlDonePromise.resolve()
}
})
function handleInjectedHtml() {
router.serverSsr!.injectedHtml.forEach((promise) => {
processingCount++

promise
.then((html) => {
if (isAppRendering) {
routerStreamBuffer += html
} else {
finalPassThrough.write(html)
}
})
.catch(injectedHtmlDonePromise.reject)
.finally(() => {
processingCount--

if (!isAppRendering && processingCount === 0) {
injectedHtmlDonePromise.resolve()
}
})
})
router.serverSsr!.injectedHtml = []
}

injectedHtmlDonePromise
Expand All @@ -176,7 +181,12 @@ export function transformStreamWithRouter(
console.error('Error reading routerStream:', err)
finalPassThrough.destroy(err)
})
.finally(() => stopListeningToInjectedHtml?.())
.finally(() => {
if (stopListeningToInjectedHtml) {
stopListeningToInjectedHtml()
stopListeningToInjectedHtml = undefined
}
})

// Transform the appStream
readStream(appStream, {
Expand Down
10 changes: 7 additions & 3 deletions packages/router-ssr-query-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,14 @@ export function setupCoreRouterSsrQueryIntegration<TRouter extends AnyRouter>({
if (router.isServer) {
const sentQueries = new Set<string>()
const queryStream = createPushableStream()

let unsubscribe: (() => void) | undefined = undefined
router.options.dehydrate =
async (): Promise<DehydratedRouterQueryState> => {
router.serverSsr!.onRenderFinished(() => queryStream.close())
router.serverSsr!.onRenderFinished(() => {
queryStream.close()
unsubscribe?.()
unsubscribe = undefined
})
const ogDehydrated = await ogDehydrate?.()

const dehydratedRouter = {
Expand Down Expand Up @@ -70,7 +74,7 @@ export function setupCoreRouterSsrQueryIntegration<TRouter extends AnyRouter>({
},
})

queryClient.getQueryCache().subscribe((event) => {
unsubscribe = queryClient.getQueryCache().subscribe((event) => {
// before rendering starts, we do not stream individual queries
// instead we dehydrate the entire query client in router's dehydrate()
// if attachRouterServerSsrUtils() has not been called yet, `router.serverSsr` will be undefined and we also do not stream
Expand Down
Loading