diff --git a/package.json b/package.json index de576cd159bd..b8b763c426b6 100644 --- a/package.json +++ b/package.json @@ -198,16 +198,16 @@ "random-seed": "0.3.0", "react": "18.2.0", "react-17": "npm:react@17.0.2", - "react-builtin": "npm:react@18.3.0-canary-60a927d04-20240113", + "react-builtin": "npm:react@18.3.0-canary-2bc7d336a-20240205", "react-dom": "18.2.0", "react-dom-17": "npm:react-dom@17.0.2", - "react-dom-builtin": "npm:react-dom@18.3.0-canary-60a927d04-20240113", - "react-dom-experimental-builtin": "npm:react-dom@0.0.0-experimental-60a927d04-20240113", - "react-experimental-builtin": "npm:react@0.0.0-experimental-60a927d04-20240113", - "react-server-dom-turbopack": "18.3.0-canary-60a927d04-20240113", - "react-server-dom-turbopack-experimental": "npm:react-server-dom-turbopack@0.0.0-experimental-60a927d04-20240113", - "react-server-dom-webpack": "18.3.0-canary-60a927d04-20240113", - "react-server-dom-webpack-experimental": "npm:react-server-dom-webpack@0.0.0-experimental-60a927d04-20240113", + "react-dom-builtin": "npm:react-dom@18.3.0-canary-2bc7d336a-20240205", + "react-dom-experimental-builtin": "npm:react-dom@0.0.0-experimental-2bc7d336a-20240205", + "react-experimental-builtin": "npm:react@0.0.0-experimental-2bc7d336a-20240205", + "react-server-dom-turbopack": "18.3.0-canary-2bc7d336a-20240205", + "react-server-dom-turbopack-experimental": "npm:react-server-dom-turbopack@0.0.0-experimental-2bc7d336a-20240205", + "react-server-dom-webpack": "18.3.0-canary-2bc7d336a-20240205", + "react-server-dom-webpack-experimental": "npm:react-server-dom-webpack@0.0.0-experimental-2bc7d336a-20240205", "react-ssr-prepass": "1.0.8", "react-virtualized": "9.22.3", "relay-compiler": "13.0.2", @@ -217,8 +217,8 @@ "resolve-from": "5.0.0", "sass": "1.54.0", "satori": "0.10.9", - "scheduler-builtin": "npm:scheduler@0.24.0-canary-60a927d04-20240113", - "scheduler-experimental-builtin": "npm:scheduler@0.0.0-experimental-60a927d04-20240113", + "scheduler-builtin": "npm:scheduler@0.24.0-canary-2bc7d336a-20240205", + "scheduler-experimental-builtin": "npm:scheduler@0.0.0-experimental-2bc7d336a-20240205", "seedrandom": "3.0.5", "selenium-webdriver": "4.0.0-beta.4", "semver": "7.3.7", diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server-legacy.browser.development.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server-legacy.browser.development.js index f37efea75879..935e484f4a1c 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server-legacy.browser.development.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server-legacy.browser.development.js @@ -17,7 +17,7 @@ if (process.env.NODE_ENV !== "production") { var React = require("next/dist/compiled/react-experimental"); var ReactDOM = require('react-dom'); -var ReactVersion = '18.3.0-experimental-60a927d04-20240113'; +var ReactVersion = '18.3.0-experimental-2bc7d336a-20240205'; var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; @@ -1814,6 +1814,7 @@ function createRenderState$1(resumableState, nonce, externalRuntimeConfig, impor headChunks: null, externalRuntimeScript: externalRuntimeScript, bootstrapChunks: bootstrapChunks, + importMapChunks: importMapChunks, onHeaders: onHeaders, headers: headers, resets: { @@ -1828,9 +1829,7 @@ function createRenderState$1(resumableState, nonce, externalRuntimeConfig, impor style: {} }, charsetChunks: [], - preconnectChunks: [], - importMapChunks: importMapChunks, - preloadChunks: [], + viewportChunks: [], hoistableChunks: [], // cleared on flush preconnects: new Set(), @@ -1849,7 +1848,7 @@ function createRenderState$1(resumableState, nonce, externalRuntimeConfig, impor }, nonce: nonce, // like a module global for currently rendering boundary - boundaryResources: null, + hoistableState: null, stylesToHoist: false }; @@ -2643,6 +2642,59 @@ function checkSelectProp(props, propName) { } } +function pushStartAnchor(target, props) { + target.push(startChunkForTag('a')); + var children = null; + var innerHTML = null; + + for (var propKey in props) { + if (hasOwnProperty.call(props, propKey)) { + var propValue = props[propKey]; + + if (propValue == null) { + continue; + } + + switch (propKey) { + case 'children': + children = propValue; + break; + + case 'dangerouslySetInnerHTML': + innerHTML = propValue; + break; + + case 'href': + if (propValue === '') { + // Empty `href` is special on anchors so we're short-circuiting here. + // On other tags it should trigger a warning + pushStringAttribute(target, 'href', ''); + } else { + pushAttribute(target, propKey, propValue); + } + + break; + + default: + pushAttribute(target, propKey, propValue); + break; + } + } + } + + target.push(endOfStartTag); + pushInnerHTML(target, innerHTML, children); + + if (typeof children === 'string') { + // Special case children as a string to avoid the unnecessary comment. + // TODO: Remove this special case after the general optimization is in place. + target.push(stringToChunk(encodeHTMLTextNode(children))); + return null; + } + + return children; +} + function pushStartSelect(target, props) { { checkControlledValueProps('select', props); @@ -3283,7 +3335,7 @@ function pushStartTextArea(target, props) { return null; } -function pushMeta(target, props, renderState, textEmbedded, insertionMode, noscriptTagInScope) { +function pushMeta(target, props, renderState, textEmbedded, insertionMode, noscriptTagInScope, isFallback) { { if (insertionMode === SVG_MODE || noscriptTagInScope || props.itemProp != null) { return pushSelfClosing(target, props, 'meta'); @@ -3294,11 +3346,24 @@ function pushMeta(target, props, renderState, textEmbedded, insertionMode, noscr target.push(textSeparator); } - if (typeof props.charSet === 'string') { + if (isFallback) { + // Hoistable Elements for fallbacks are simply omitted. we don't want to emit them early + // because they are likely superceded by primary content and we want to avoid needing to clean + // them up when the primary content is ready. They are never hydrated on the client anyway because + // boundaries in fallback are awaited or client render, in either case there is never hydration + return null; + } else if (typeof props.charSet === 'string') { + // "charset" Should really be config and not picked up from tags however since this is + // the only way to embed the tag today we flush it on a special queue on the Request so it + // can go before everything else. Like viewport this means that the tag will escape it's + // parent container. return pushSelfClosing(renderState.charsetChunks, props, 'meta'); } else if (props.name === 'viewport') { - // "viewport" isn't related to preconnect but it has the right priority - return pushSelfClosing(renderState.preconnectChunks, props, 'meta'); + // "viewport" is flushed on the Request so it can go earlier that Float resources that + // might be affected by it. This means it can escape the boundary it is rendered within. + // This is a pragmatic solution to viewport being incredibly sensitive to document order + // without requiring all hoistables to be flushed too early. + return pushSelfClosing(renderState.viewportChunks, props, 'meta'); } else { return pushSelfClosing(renderState.hoistableChunks, props, 'meta'); } @@ -3306,7 +3371,7 @@ function pushMeta(target, props, renderState, textEmbedded, insertionMode, noscr } } -function pushLink(target, props, resumableState, renderState, textEmbedded, insertionMode, noscriptTagInScope) { +function pushLink(target, props, resumableState, renderState, hoistableState, textEmbedded, insertionMode, noscriptTagInScope, isFallback) { { var rel = props.rel; var href = props.href; @@ -3398,8 +3463,8 @@ function pushLink(target, props, resumableState, renderState, textEmbedded, inse styleQueue.sheets.set(key, resource); - if (renderState.boundaryResources) { - renderState.boundaryResources.stylesheets.add(resource); + if (hoistableState) { + hoistableState.stylesheets.add(resource); } } else { // We need to track whether this boundary should wait on this resource or not. @@ -3411,8 +3476,8 @@ function pushLink(target, props, resumableState, renderState, textEmbedded, inse var _resource = styleQueue.sheets.get(key); if (_resource) { - if (renderState.boundaryResources) { - renderState.boundaryResources.stylesheets.add(_resource); + if (hoistableState) { + hoistableState.stylesheets.add(_resource); } } } @@ -3439,16 +3504,14 @@ function pushLink(target, props, resumableState, renderState, textEmbedded, inse target.push(textSeparator); } - switch (props.rel) { - case 'preconnect': - case 'dns-prefetch': - return pushLinkImpl(renderState.preconnectChunks, props); - - case 'preload': - return pushLinkImpl(renderState.preloadChunks, props); - - default: - return pushLinkImpl(renderState.hoistableChunks, props); + if (isFallback) { + // Hoistable Elements for fallbacks are simply omitted. we don't want to emit them early + // because they are likely superceded by primary content and we want to avoid needing to clean + // them up when the primary content is ready. They are never hydrated on the client anyway because + // boundaries in fallback are awaited or client render, in either case there is never hydration + return null; + } else { + return pushLinkImpl(renderState.hoistableChunks, props); } } } @@ -3481,7 +3544,7 @@ function pushLinkImpl(target, props) { return null; } -function pushStyle(target, props, resumableState, renderState, textEmbedded, insertionMode, noscriptTagInScope) { +function pushStyle(target, props, resumableState, renderState, hoistableState, textEmbedded, insertionMode, noscriptTagInScope) { { if (hasOwnProperty.call(props, 'children')) { var children = props.children; @@ -3549,8 +3612,8 @@ function pushStyle(target, props, resumableState, renderState, textEmbedded, ins // it. However, it's possible when you resume that the style has already been emitted // and then it wouldn't be recreated in the RenderState and there's no need to track // it again since we should've hoisted it to the shell already. - if (renderState.boundaryResources) { - renderState.boundaryResources.styles.add(styleQueue); + if (hoistableState) { + hoistableState.styles.add(styleQueue); } } @@ -3796,7 +3859,7 @@ function pushStartMenuItem(target, props) { return null; } -function pushTitle(target, props, renderState, insertionMode, noscriptTagInScope) { +function pushTitle(target, props, renderState, insertionMode, noscriptTagInScope, isFallback) { { if (hasOwnProperty.call(props, 'children')) { var children = props.children; @@ -3820,8 +3883,15 @@ function pushTitle(target, props, renderState, insertionMode, noscriptTagInScope { if (insertionMode !== SVG_MODE && !noscriptTagInScope && props.itemProp == null) { - pushTitleImpl(renderState.hoistableChunks, props); - return null; + if (isFallback) { + // Hoistable Elements for fallbacks are simply omitted. we don't want to emit them early + // because they are likely superceded by primary content and we want to avoid needing to clean + // them up when the primary content is ready. They are never hydrated on the client anyway because + // boundaries in fallback are awaited or client render, in either case there is never hydration + return null; + } else { + pushTitleImpl(renderState.hoistableChunks, props); + } } else { return pushTitleImpl(target, props); } @@ -4218,7 +4288,7 @@ function startChunkForTag(tag) { return tagStartChunk; } -function pushStartInstance(target, type, props, resumableState, renderState, formatContext, textEmbedded) { +function pushStartInstance(target, type, props, resumableState, renderState, hoistableState, formatContext, textEmbedded, isFallback) { { validateProperties$2(type, props); validateProperties$1(type, props); @@ -4240,7 +4310,14 @@ function pushStartInstance(target, type, props, resumableState, renderState, for case 'span': case 'svg': case 'path': + // Fast track very common tags + break; + case 'a': + { + return pushStartAnchor(target, props); + } + case 'g': case 'p': case 'li': @@ -4270,19 +4347,19 @@ function pushStartInstance(target, type, props, resumableState, renderState, for return pushStartMenuItem(target, props); case 'title': - return pushTitle(target, props, renderState, formatContext.insertionMode, !!(formatContext.tagScope & NOSCRIPT_SCOPE)) ; + return pushTitle(target, props, renderState, formatContext.insertionMode, !!(formatContext.tagScope & NOSCRIPT_SCOPE), isFallback) ; case 'link': - return pushLink(target, props, resumableState, renderState, textEmbedded, formatContext.insertionMode, !!(formatContext.tagScope & NOSCRIPT_SCOPE)); + return pushLink(target, props, resumableState, renderState, hoistableState, textEmbedded, formatContext.insertionMode, !!(formatContext.tagScope & NOSCRIPT_SCOPE), isFallback); case 'script': return pushScript(target, props, resumableState, renderState, textEmbedded, formatContext.insertionMode, !!(formatContext.tagScope & NOSCRIPT_SCOPE)) ; case 'style': - return pushStyle(target, props, resumableState, renderState, textEmbedded, formatContext.insertionMode, !!(formatContext.tagScope & NOSCRIPT_SCOPE)); + return pushStyle(target, props, resumableState, renderState, hoistableState, textEmbedded, formatContext.insertionMode, !!(formatContext.tagScope & NOSCRIPT_SCOPE)); case 'meta': - return pushMeta(target, props, renderState, textEmbedded, formatContext.insertionMode, !!(formatContext.tagScope & NOSCRIPT_SCOPE)); + return pushMeta(target, props, renderState, textEmbedded, formatContext.insertionMode, !!(formatContext.tagScope & NOSCRIPT_SCOPE), isFallback); // Newline eating tags case 'listing': @@ -4710,7 +4787,7 @@ var completeBoundaryWithStylesData1 = stringToPrecomputedChunk('')} +function $b(a,b,c,d){switch(c.insertionMode){case 0:case 1:case 2:return a.push('