From fbb449102afa372a0d16fcf10a3c3bcaa06631aa Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Thu, 17 Mar 2022 20:45:09 +0100 Subject: [PATCH 1/3] change the timing for clearing the inlined data buffer --- packages/next/client/index.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/next/client/index.tsx b/packages/next/client/index.tsx index c00d17f7276..019bee1f751 100644 --- a/packages/next/client/index.tsx +++ b/packages/next/client/index.tsx @@ -710,6 +710,7 @@ if (process.env.__NEXT_RSC) { if (initialServerDataWriter && !initialServerDataWriter.closed) { initialServerDataWriter.close() } + initialServerDataBuffer = undefined }, false ) @@ -771,9 +772,6 @@ if (process.env.__NEXT_RSC) { React.useEffect(() => { rscCache.delete(cacheKey) }) - React.useEffect(() => { - initialServerDataBuffer = undefined - }, []) const response = useServerResponse(cacheKey, serialized) const root = response.readRoot() return root From 31a1a6941605950b8440ce60b08ffc1df18dcef8 Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Thu, 17 Mar 2022 22:42:44 +0100 Subject: [PATCH 2/3] add comment --- packages/next/client/index.tsx | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/packages/next/client/index.tsx b/packages/next/client/index.tsx index 019bee1f751..9dd60546f86 100644 --- a/packages/next/client/index.tsx +++ b/packages/next/client/index.tsx @@ -678,9 +678,13 @@ if (process.env.__NEXT_RSC) { } = require('next/dist/compiled/react-server-dom-webpack') const encoder = new TextEncoder() + let initialServerDataBuffer: string[] | undefined = undefined let initialServerDataWriter: WritableStreamDefaultWriter | undefined = undefined + let initialServerDataLoaded = false + let initialServerDataFlushed = false + function nextServerDataCallback(seg: [number, string, string]) { if (seg[0] === 0) { initialServerDataBuffer = [] @@ -695,22 +699,40 @@ if (process.env.__NEXT_RSC) { } } } + + // 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. + // For streaming, the former is called first due to partial hydration. + // For non-streaming, the latter can be called first. + // Hence, we use two variables `initialServerDataLoaded` and + // `initialServerDataFlushed` to make sure the writer will be closed and + // `initialServerDataBuffer` will be cleared in the right time. function nextServerDataRegisterWriter(writer: WritableStreamDefaultWriter) { if (initialServerDataBuffer) { initialServerDataBuffer.forEach((val) => { writer.write(encoder.encode(val)) }) + if (initialServerDataLoaded && !initialServerDataFlushed) { + writer.close() + initialServerDataFlushed = true + initialServerDataBuffer = undefined + } } + initialServerDataWriter = writer } + // When `DOMContentLoaded`, we can close all pending writers to finish hydration. document.addEventListener( 'DOMContentLoaded', function () { - if (initialServerDataWriter && !initialServerDataWriter.closed) { + if (initialServerDataWriter && !initialServerDataFlushed) { initialServerDataWriter.close() + initialServerDataFlushed = true + initialServerDataBuffer = undefined } - initialServerDataBuffer = undefined + initialServerDataLoaded = true }, false ) From 58c7c2e9ac44bb61dcc3b3e8b4d34ff9dee6e044 Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Fri, 18 Mar 2022 02:16:15 +0100 Subject: [PATCH 3/3] fix dom loaded race condition --- packages/next/client/index.tsx | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/packages/next/client/index.tsx b/packages/next/client/index.tsx index 9dd60546f86..cd2f3fc315b 100644 --- a/packages/next/client/index.tsx +++ b/packages/next/client/index.tsx @@ -724,18 +724,20 @@ if (process.env.__NEXT_RSC) { } // When `DOMContentLoaded`, we can close all pending writers to finish hydration. - document.addEventListener( - 'DOMContentLoaded', - function () { - if (initialServerDataWriter && !initialServerDataFlushed) { - initialServerDataWriter.close() - initialServerDataFlushed = true - initialServerDataBuffer = undefined - } - initialServerDataLoaded = true - }, - false - ) + const DOMContentLoaded = function () { + if (initialServerDataWriter && !initialServerDataFlushed) { + initialServerDataWriter.close() + initialServerDataFlushed = true + initialServerDataBuffer = undefined + } + initialServerDataLoaded = true + } + // It's possible that the DOM is already loaded. + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', DOMContentLoaded, false) + } else { + DOMContentLoaded() + } const nextServerDataLoadingGlobal = ((self as any).__next_s = (self as any).__next_s || [])