From 56e40007827c0297058a49f32e26834a28e03867 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Wed, 15 May 2024 16:39:17 +0200 Subject: [PATCH 1/3] Trigger error for ReadableStreamController on client when stream is not finished --- packages/next/src/client/app-index.tsx | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/next/src/client/app-index.tsx b/packages/next/src/client/app-index.tsx index 9058c233bf5d1..4f303f542b95a 100644 --- a/packages/next/src/client/app-index.tsx +++ b/packages/next/src/client/app-index.tsx @@ -90,6 +90,11 @@ function nextServerDataCallback( } } +function isStreamErrorOrUnfinished(ctr: ReadableStreamDefaultController) { + // If `desiredSize` is null, it means the stream is closed or errored. If it is lower than 0, the stream is still unfinished. + return ctr.desiredSize === null || ctr.desiredSize < 0 +} + // There might be race conditions between `nextServerDataRegisterWriter` and // `DOMContentLoaded`. The former will be called when React starts to hydrate // the root, the latter will be called when the DOM is fully loaded. @@ -104,7 +109,15 @@ function nextServerDataRegisterWriter(ctr: ReadableStreamDefaultController) { ctr.enqueue(typeof val === 'string' ? encoder.encode(val) : val) }) if (initialServerDataLoaded && !initialServerDataFlushed) { - ctr.close() + if (isStreamErrorOrUnfinished(ctr)) { + ctr.error( + new Error( + 'The connection to the page was unexpectedly closed, possibly due to the stop button being clicked, loss of Wi-Fi, or an unstable internet connection.' + ) + ) + } else { + ctr.close() + } initialServerDataFlushed = true initialServerDataBuffer = undefined } From a52c2d5c8c11d5bc7724b327572b7d313cb9f66e Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Thu, 16 May 2024 15:37:51 +0200 Subject: [PATCH 2/3] delay dom loaded --- packages/next/src/client/app-index.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/next/src/client/app-index.tsx b/packages/next/src/client/app-index.tsx index 4f303f542b95a..025a87baa2016 100644 --- a/packages/next/src/client/app-index.tsx +++ b/packages/next/src/client/app-index.tsx @@ -135,11 +135,14 @@ const DOMContentLoaded = function () { } initialServerDataLoaded = true } + +const queueTask = queueMicrotask || ((fn: Function) => setTimeout(fn, 0)) + // It's possible that the DOM is already loaded. if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', DOMContentLoaded, false) } else { - DOMContentLoaded() + queueTask(DOMContentLoaded) } const nextServerDataLoadingGlobal = ((self as any).__next_f = From db99c438f672271f024932e50341d1ea9c1b3784 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Thu, 16 May 2024 18:31:10 +0200 Subject: [PATCH 3/3] delay in macro task --- packages/next/src/client/app-index.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/next/src/client/app-index.tsx b/packages/next/src/client/app-index.tsx index 025a87baa2016..bbab03a359092 100644 --- a/packages/next/src/client/app-index.tsx +++ b/packages/next/src/client/app-index.tsx @@ -136,13 +136,12 @@ const DOMContentLoaded = function () { initialServerDataLoaded = true } -const queueTask = queueMicrotask || ((fn: Function) => setTimeout(fn, 0)) - // It's possible that the DOM is already loaded. if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', DOMContentLoaded, false) } else { - queueTask(DOMContentLoaded) + // Delayed in marco task to ensure it's executed later than hydration + setTimeout(DOMContentLoaded) } const nextServerDataLoadingGlobal = ((self as any).__next_f =