@@ -684,16 +684,25 @@ export function completeResumableState(resumableState: ResumableState): void {
684684 resumableState . bootstrapModules = undefined ;
685685}
686686
687+ const NoContribution /* */ = 0b000 ;
688+ const HTMLContribution /* */ = 0b001 ;
689+ const HeadContribution /* */ = 0b010 ;
690+ const BodyContribution /* */ = 0b100 ;
691+ const TotalContribution =
692+ HTMLContribution | HeadContribution | BodyContribution ;
693+
687694export type PreambleState = {
688695 htmlChunks : null | Array < Chunk | PrecomputedChunk > ,
689696 headChunks : null | Array < Chunk | PrecomputedChunk > ,
690697 bodyChunks : null | Array < Chunk | PrecomputedChunk > ,
698+ contribution : number ,
691699} ;
692700export function createPreambleState ( ) : PreambleState {
693701 return {
694702 htmlChunks : null ,
695703 headChunks : null ,
696704 bodyChunks : null ,
705+ contribution : NoContribution ,
697706 } ;
698707}
699708
@@ -3227,7 +3236,7 @@ function pushStartHead(
32273236 throw new Error ( `The ${ '`<head>`' } tag may only be rendered once.` ) ;
32283237 }
32293238 preamble . headChunks = [ ] ;
3230- return pushStartGenericElement ( preamble . headChunks , props , 'head' ) ;
3239+ return pushStartSingletonElement ( preamble . headChunks , props , 'head' ) ;
32313240 } else {
32323241 // This <head> is deep and is likely just an error. we emit it inline though.
32333242 // Validation should warn that this tag is the the wrong spot.
@@ -3251,7 +3260,7 @@ function pushStartBody(
32513260 }
32523261
32533262 preamble . bodyChunks = [ ] ;
3254- return pushStartGenericElement ( preamble . bodyChunks , props , 'body' ) ;
3263+ return pushStartSingletonElement ( preamble . bodyChunks , props , 'body' ) ;
32553264 } else {
32563265 // This <head> is deep and is likely just an error. we emit it inline though.
32573266 // Validation should warn that this tag is the the wrong spot.
@@ -3275,7 +3284,7 @@ function pushStartHtml(
32753284 }
32763285
32773286 preamble . htmlChunks = [ DOCTYPE ] ;
3278- return pushStartGenericElement ( preamble . htmlChunks , props , 'html' ) ;
3287+ return pushStartSingletonElement ( preamble . htmlChunks , props , 'html' ) ;
32793288 } else {
32803289 // This <html> is deep and is likely just an error. we emit it inline though.
32813290 // Validation should warn that this tag is the the wrong spot.
@@ -3416,6 +3425,43 @@ function pushScriptImpl(
34163425 return null ;
34173426}
34183427
3428+ // This is a fork of pushStartGenericElement because we don't ever want to do
3429+ // the children as strign optimization on that path when rendering singletons.
3430+ // When we eliminate that special path we can delete this fork and unify it again
3431+ function pushStartSingletonElement (
3432+ target : Array < Chunk | PrecomputedChunk > ,
3433+ props : Object ,
3434+ tag : string ,
3435+ ) : ReactNodeList {
3436+ target . push ( startChunkForTag ( tag ) ) ;
3437+
3438+ let children = null ;
3439+ let innerHTML = null ;
3440+ for ( const propKey in props ) {
3441+ if ( hasOwnProperty . call ( props , propKey ) ) {
3442+ const propValue = props [ propKey ] ;
3443+ if ( propValue == null ) {
3444+ continue ;
3445+ }
3446+ switch ( propKey ) {
3447+ case 'children ':
3448+ children = propValue ;
3449+ break ;
3450+ case 'dangerouslySetInnerHTML ':
3451+ innerHTML = propValue ;
3452+ break ;
3453+ default :
3454+ pushAttribute ( target , propKey , propValue ) ;
3455+ break ;
3456+ }
3457+ }
3458+ }
3459+
3460+ target . push ( endOfStartTag ) ;
3461+ pushInnerHTML ( target , innerHTML , children ) ;
3462+ return children ;
3463+ }
3464+
34193465function pushStartGenericElement (
34203466 target : Array < Chunk | PrecomputedChunk > ,
34213467 props : Object ,
@@ -3907,14 +3953,17 @@ export function hoistPreambleState(
39073953 preambleState : PreambleState ,
39083954) {
39093955 const rootPreamble = renderState . preamble ;
3910- if ( rootPreamble . htmlChunks === null ) {
3956+ if ( rootPreamble . htmlChunks === null && preambleState . htmlChunks ) {
39113957 rootPreamble . htmlChunks = preambleState . htmlChunks ;
3958+ preambleState . contribution |= HTMLContribution ;
39123959 }
3913- if ( rootPreamble . headChunks === null ) {
3960+ if ( rootPreamble . headChunks === null && preambleState . headChunks ) {
39143961 rootPreamble . headChunks = preambleState . headChunks ;
3962+ preambleState . contribution |= HeadContribution ;
39153963 }
3916- if ( rootPreamble . bodyChunks === null ) {
3964+ if ( rootPreamble . bodyChunks === null && preambleState . bodyChunks ) {
39173965 rootPreamble . bodyChunks = preambleState . bodyChunks ;
3966+ preambleState . contribution |= BodyContribution ;
39183967 }
39193968}
39203969
@@ -4005,6 +4054,14 @@ const clientRenderedSuspenseBoundaryError1D =
40054054const clientRenderedSuspenseBoundaryError2 =
40064055 stringToPrecomputedChunk ( '></template>' ) ;
40074056
4057+ const boundaryPreambleContributionChunkTotal =
4058+ stringToPrecomputedChunk ( '<!--P-->' ) ;
4059+ const boundaryPreambleContributionChunkStart =
4060+ stringToPrecomputedChunk ( '<!--P' ) ;
4061+ const ContributionChunk = stringToPrecomputedChunk ( '1' ) ;
4062+ const NonContributionChunk = stringToPrecomputedChunk ( ' ' ) ;
4063+ const boundaryPreambleContributionChunkEnd = stringToPrecomputedChunk ( '-->' ) ;
4064+
40084065export function writeStartCompletedSuspenseBoundary (
40094066 destination : Destination ,
40104067 renderState : RenderState ,
@@ -4091,7 +4148,11 @@ export function writeStartClientRenderedSuspenseBoundary(
40914148export function writeEndCompletedSuspenseBoundary (
40924149 destination : Destination ,
40934150 renderState : RenderState ,
4151+ preambleState : null | PreambleState ,
40944152) : boolean {
4153+ if ( preambleState ) {
4154+ writePreambleContribution ( destination , preambleState ) ;
4155+ }
40954156 return writeChunkAndReturn ( destination , endSuspenseBoundary ) ;
40964157}
40974158export function writeEndPendingSuspenseBoundary (
@@ -4103,9 +4164,47 @@ export function writeEndPendingSuspenseBoundary(
41034164export function writeEndClientRenderedSuspenseBoundary (
41044165 destination : Destination ,
41054166 renderState : RenderState ,
4167+ preambleState : null | PreambleState ,
41064168) : boolean {
4169+ if ( preambleState ) {
4170+ writePreambleContribution ( destination , preambleState ) ;
4171+ }
41074172 return writeChunkAndReturn ( destination , endSuspenseBoundary ) ;
41084173}
4174+ function writePreambleContribution (
4175+ destination : Destination ,
4176+ preambleState : PreambleState ,
4177+ ) {
4178+ const contribution = preambleState . contribution ;
4179+ if ( contribution !== NoContribution ) {
4180+ if ( contribution === TotalContribution ) {
4181+ // We shortcut the preamble marker for boundaries that contribute the entire preamble
4182+ // since we expect this to be the most common case
4183+ writeChunk ( destination , boundaryPreambleContributionChunkTotal ) ;
4184+ } else {
4185+ writeChunk ( destination , boundaryPreambleContributionChunkStart ) ;
4186+ writeChunk (
4187+ destination ,
4188+ contribution & HTMLContribution
4189+ ? ContributionChunk
4190+ : NonContributionChunk ,
4191+ ) ;
4192+ writeChunk (
4193+ destination ,
4194+ contribution & HeadContribution
4195+ ? ContributionChunk
4196+ : NonContributionChunk ,
4197+ ) ;
4198+ writeChunk (
4199+ destination ,
4200+ contribution & BodyContribution
4201+ ? ContributionChunk
4202+ : NonContributionChunk ,
4203+ ) ;
4204+ writeChunk ( destination , boundaryPreambleContributionChunkEnd ) ;
4205+ }
4206+ }
4207+ }
41094208
41104209const startSegmentHTML = stringToPrecomputedChunk ( '<div hidden id="' ) ;
41114210const startSegmentHTML2 = stringToPrecomputedChunk ( '">' ) ;
0 commit comments