From 70b0bbda767ed016925889e8952b10f49921c0cf Mon Sep 17 00:00:00 2001 From: mofeiZ <34200447+mofeiZ@users.noreply.github.com> Date: Tue, 21 Feb 2023 09:10:23 -0800 Subject: [PATCH] [fizz][external-runtime] Fix: process mutation records before disconnecting (#26169) > All notifications of mutations that have already been detected, but not yet reported to the observer, are discarded. To hold on to and handle the detected but unreported mutations, use the takeRecords() method. > -- ([Mozilla docs for disconnect]( https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver/disconnect)) Fizz external runtime needs to process mutation records (representing potential Fizz instructions) before calling `disconnect()`. We currently do not do this (and might drop some instructions). --- .../src/server/ReactDOMServerExternalRuntime.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/react-dom-bindings/src/server/ReactDOMServerExternalRuntime.js b/packages/react-dom-bindings/src/server/ReactDOMServerExternalRuntime.js index 638b653ef66c9..08012fbc1a248 100644 --- a/packages/react-dom-bindings/src/server/ReactDOMServerExternalRuntime.js +++ b/packages/react-dom-bindings/src/server/ReactDOMServerExternalRuntime.js @@ -35,6 +35,8 @@ if (document.readyState === 'loading') { installFizzInstrObserver(document.body); } handleExistingNodes(); + // We can call disconnect without takeRecord here, + // since we only expect a single document.body domBodyObserver.disconnect(); } }); @@ -54,7 +56,7 @@ function handleExistingNodes() { } function installFizzInstrObserver(target /*: Node */) { - const fizzInstrObserver = new MutationObserver(mutations => { + const handleMutations = (mutations /*: Array */) => { for (let i = 0; i < mutations.length; i++) { const addedNodes = mutations[i].addedNodes; for (let j = 0; j < addedNodes.length; j++) { @@ -63,13 +65,16 @@ function installFizzInstrObserver(target /*: Node */) { } } } - }); + }; + + const fizzInstrObserver = new MutationObserver(handleMutations); // We assume that instruction data nodes are eventually appended to the // body, even if Fizz is streaming to a shell / subtree. fizzInstrObserver.observe(target, { childList: true, }); window.addEventListener('DOMContentLoaded', () => { + handleMutations(fizzInstrObserver.takeRecords()); fizzInstrObserver.disconnect(); }); }