From 6b8275d33e9cb8cff6b7afd6ec19a53336e2a829 Mon Sep 17 00:00:00 2001 From: jerrydev0927 Date: Thu, 12 Oct 2023 22:07:22 +0000 Subject: [PATCH] [Fizz] Fix children rendering in custom elements with `enableCustomElementPropertySupport` (#27511) The `enableCustomElementPropertySupport` flag changes React's handling of custom elements in a way that is more useful that just treating every prop as an attribute. However when server rendering we have no choice but to serialize props as attributes. When this flag is on and React supports more prop types on the client like functions and objects the server implementation needs to be a bit more naunced in how it renders these components. With this flag on `false`, function, and object props are omitted entirely and `true` is normalized to `""`. There was a bug however in the implementation which caused children more complex than a single string to be omitted because it matched the object type filter. This change reorganizes the code a bit to put these filters in the default prop handline case, leaving children, style, and innerHTML to be handled via normal logic. fixes: https://github.com/facebook/react/issues/27286 DiffTrain build for [bb778528d1ca22b44dad832f0258aaa4c0e6d4a4](https://github.com/facebook/react/commit/bb778528d1ca22b44dad832f0258aaa4c0e6d4a4) --- compiled/facebook-www/REVISION | 2 +- compiled/facebook-www/ReactART-dev.modern.js | 2 +- compiled/facebook-www/ReactART-prod.modern.js | 4 +- .../ReactDOMServer-dev.classic.js | 47 ++++++----- .../facebook-www/ReactDOMServer-dev.modern.js | 47 ++++++----- .../ReactDOMServer-prod.classic.js | 78 +++++++++---------- .../ReactDOMServer-prod.modern.js | 78 +++++++++---------- .../ReactDOMServerStreaming-dev.modern.js | 45 +++++------ .../ReactDOMServerStreaming-prod.modern.js | 40 +++++----- 9 files changed, 161 insertions(+), 182 deletions(-) diff --git a/compiled/facebook-www/REVISION b/compiled/facebook-www/REVISION index 6e4bf763a0..8501bbd590 100644 --- a/compiled/facebook-www/REVISION +++ b/compiled/facebook-www/REVISION @@ -1 +1 @@ -1fc58281af73ca4507c41d53a3e08dc2038b0c1f +bb778528d1ca22b44dad832f0258aaa4c0e6d4a4 diff --git a/compiled/facebook-www/ReactART-dev.modern.js b/compiled/facebook-www/ReactART-dev.modern.js index dc2932879d..b8f5956696 100644 --- a/compiled/facebook-www/ReactART-dev.modern.js +++ b/compiled/facebook-www/ReactART-dev.modern.js @@ -69,7 +69,7 @@ function _assertThisInitialized(self) { return self; } -var ReactVersion = "18.3.0-www-modern-5fb559f6"; +var ReactVersion = "18.3.0-www-modern-70e823a6"; var LegacyRoot = 0; var ConcurrentRoot = 1; diff --git a/compiled/facebook-www/ReactART-prod.modern.js b/compiled/facebook-www/ReactART-prod.modern.js index 6ca920cfab..1dd2990b15 100644 --- a/compiled/facebook-www/ReactART-prod.modern.js +++ b/compiled/facebook-www/ReactART-prod.modern.js @@ -9780,7 +9780,7 @@ var slice = Array.prototype.slice, return null; }, bundleType: 0, - version: "18.3.0-www-modern-21a11200", + version: "18.3.0-www-modern-7f660f7a", rendererPackageName: "react-art" }; var internals$jscomp$inline_1286 = { @@ -9811,7 +9811,7 @@ var internals$jscomp$inline_1286 = { scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-www-modern-21a11200" + reconcilerVersion: "18.3.0-www-modern-7f660f7a" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { var hook$jscomp$inline_1287 = __REACT_DEVTOOLS_GLOBAL_HOOK__; diff --git a/compiled/facebook-www/ReactDOMServer-dev.classic.js b/compiled/facebook-www/ReactDOMServer-dev.classic.js index 0eff12244e..fe09c7bc1a 100644 --- a/compiled/facebook-www/ReactDOMServer-dev.classic.js +++ b/compiled/facebook-www/ReactDOMServer-dev.classic.js @@ -19,7 +19,7 @@ if (__DEV__) { var React = require("react"); var ReactDOM = require("react-dom"); -var ReactVersion = "18.3.0-www-classic-0d5846ce"; +var ReactVersion = "18.3.0-www-classic-c2645119"; // This refers to a WWW module. var warningWWW = require("warning"); @@ -4715,29 +4715,7 @@ function pushStartCustomElement(target, props, tag) { continue; } - if ( - enableCustomElementPropertySupport && - (typeof propValue === "function" || typeof propValue === "object") - ) { - // It is normal to render functions and objects on custom elements when - // client rendering, but when server rendering the output isn't useful, - // so skip it. - continue; - } - - if (enableCustomElementPropertySupport && propValue === false) { - continue; - } - - if (enableCustomElementPropertySupport && propValue === true) { - propValue = ""; - } - - if (enableCustomElementPropertySupport && propKey === "className") { - // className gets rendered as class on the client, so it should be - // rendered as class on the server. - propKey = "class"; - } + var attributeName = propKey; switch (propKey) { case "children": @@ -4757,15 +4735,34 @@ function pushStartCustomElement(target, props, tag) { // Ignored. These are built-in to React on the client. break; + case "className": + if (enableCustomElementPropertySupport) { + // className gets rendered as class on the client, so it should be + // rendered as class on the server. + attributeName = "class"; + } + + // intentional fallthrough + default: if ( isAttributeNameSafe(propKey) && typeof propValue !== "function" && typeof propValue !== "symbol" ) { + if (enableCustomElementPropertySupport) { + if (propValue === false) { + continue; + } else if (propValue === true) { + propValue = ""; + } else if (typeof propValue === "object") { + continue; + } + } + target.push( attributeSeparator, - stringToChunk(propKey), + stringToChunk(attributeName), attributeAssign, stringToChunk(escapeTextForBrowser(propValue)), attributeEnd diff --git a/compiled/facebook-www/ReactDOMServer-dev.modern.js b/compiled/facebook-www/ReactDOMServer-dev.modern.js index 3255baf9db..02a9879f43 100644 --- a/compiled/facebook-www/ReactDOMServer-dev.modern.js +++ b/compiled/facebook-www/ReactDOMServer-dev.modern.js @@ -19,7 +19,7 @@ if (__DEV__) { var React = require("react"); var ReactDOM = require("react-dom"); -var ReactVersion = "18.3.0-www-modern-5fb559f6"; +var ReactVersion = "18.3.0-www-modern-70e823a6"; // This refers to a WWW module. var warningWWW = require("warning"); @@ -4715,29 +4715,7 @@ function pushStartCustomElement(target, props, tag) { continue; } - if ( - enableCustomElementPropertySupport && - (typeof propValue === "function" || typeof propValue === "object") - ) { - // It is normal to render functions and objects on custom elements when - // client rendering, but when server rendering the output isn't useful, - // so skip it. - continue; - } - - if (enableCustomElementPropertySupport && propValue === false) { - continue; - } - - if (enableCustomElementPropertySupport && propValue === true) { - propValue = ""; - } - - if (enableCustomElementPropertySupport && propKey === "className") { - // className gets rendered as class on the client, so it should be - // rendered as class on the server. - propKey = "class"; - } + var attributeName = propKey; switch (propKey) { case "children": @@ -4757,15 +4735,34 @@ function pushStartCustomElement(target, props, tag) { // Ignored. These are built-in to React on the client. break; + case "className": + if (enableCustomElementPropertySupport) { + // className gets rendered as class on the client, so it should be + // rendered as class on the server. + attributeName = "class"; + } + + // intentional fallthrough + default: if ( isAttributeNameSafe(propKey) && typeof propValue !== "function" && typeof propValue !== "symbol" ) { + if (enableCustomElementPropertySupport) { + if (propValue === false) { + continue; + } else if (propValue === true) { + propValue = ""; + } else if (typeof propValue === "object") { + continue; + } + } + target.push( attributeSeparator, - stringToChunk(propKey), + stringToChunk(attributeName), attributeAssign, stringToChunk(escapeTextForBrowser(propValue)), attributeEnd diff --git a/compiled/facebook-www/ReactDOMServer-prod.classic.js b/compiled/facebook-www/ReactDOMServer-prod.classic.js index 11e7b48d39..6e908136ec 100644 --- a/compiled/facebook-www/ReactDOMServer-prod.classic.js +++ b/compiled/facebook-www/ReactDOMServer-prod.classic.js @@ -1527,25 +1527,9 @@ function pushStartInstance( for (propKey$jscomp$9 in props) if (hasOwnProperty.call(props, propKey$jscomp$9)) { var propValue$jscomp$9 = props[propKey$jscomp$9]; - if ( - !( - null == propValue$jscomp$9 || - (enableCustomElementPropertySupport && - ("function" === typeof propValue$jscomp$9 || - "object" === typeof propValue$jscomp$9)) || - (enableCustomElementPropertySupport && - !1 === propValue$jscomp$9) - ) - ) - switch ( - (enableCustomElementPropertySupport && - !0 === propValue$jscomp$9 && - (propValue$jscomp$9 = ""), - enableCustomElementPropertySupport && - "className" === propKey$jscomp$9 && - (propKey$jscomp$9 = "class"), - propKey$jscomp$9) - ) { + if (null != propValue$jscomp$9) { + var attributeName = propKey$jscomp$9; + switch (propKey$jscomp$9) { case "children": children$jscomp$7 = propValue$jscomp$9; break; @@ -1558,18 +1542,30 @@ function pushStartInstance( case "suppressContentEditableWarning": case "suppressHydrationWarning": break; + case "className": + enableCustomElementPropertySupport && + (attributeName = "class"); default: - isAttributeNameSafe(propKey$jscomp$9) && + if ( + isAttributeNameSafe(propKey$jscomp$9) && "function" !== typeof propValue$jscomp$9 && - "symbol" !== typeof propValue$jscomp$9 && + "symbol" !== typeof propValue$jscomp$9 + ) { + if (enableCustomElementPropertySupport) + if (!1 === propValue$jscomp$9) continue; + else if (!0 === propValue$jscomp$9) + propValue$jscomp$9 = ""; + else if ("object" === typeof propValue$jscomp$9) continue; target$jscomp$0.push( " ", - propKey$jscomp$9, + attributeName, '="', escapeTextForBrowser(propValue$jscomp$9), '"' ); + } } + } } target$jscomp$0.push(">"); pushInnerHTML(target$jscomp$0, innerHTML$jscomp$6, children$jscomp$7); @@ -2291,16 +2287,16 @@ function hoistStylesheetDependency(stylesheet) { function createRenderState(resumableState, generateStaticMarkup) { var idPrefix = resumableState.idPrefix; resumableState = idPrefix + "P:"; - var JSCompiler_object_inline_segmentPrefix_1568 = idPrefix + "S:"; + var JSCompiler_object_inline_segmentPrefix_1569 = idPrefix + "S:"; idPrefix += "B:"; - var JSCompiler_object_inline_preconnects_1580 = new Set(), - JSCompiler_object_inline_fontPreloads_1581 = new Set(), - JSCompiler_object_inline_highImagePreloads_1582 = new Set(), - JSCompiler_object_inline_styles_1583 = new Map(), - JSCompiler_object_inline_bootstrapScripts_1584 = new Set(), - JSCompiler_object_inline_scripts_1585 = new Set(), - JSCompiler_object_inline_bulkPreloads_1586 = new Set(), - JSCompiler_object_inline_preloads_1587 = { + var JSCompiler_object_inline_preconnects_1581 = new Set(), + JSCompiler_object_inline_fontPreloads_1582 = new Set(), + JSCompiler_object_inline_highImagePreloads_1583 = new Set(), + JSCompiler_object_inline_styles_1584 = new Map(), + JSCompiler_object_inline_bootstrapScripts_1585 = new Set(), + JSCompiler_object_inline_scripts_1586 = new Set(), + JSCompiler_object_inline_bulkPreloads_1587 = new Set(), + JSCompiler_object_inline_preloads_1588 = { images: new Map(), stylesheets: new Map(), scripts: new Map(), @@ -2308,7 +2304,7 @@ function createRenderState(resumableState, generateStaticMarkup) { }; return { placeholderPrefix: resumableState, - segmentPrefix: JSCompiler_object_inline_segmentPrefix_1568, + segmentPrefix: JSCompiler_object_inline_segmentPrefix_1569, boundaryPrefix: idPrefix, startInlineScript: "