@@ -147,6 +147,8 @@ export type RenderState = {
147
147
// inline script streaming format, unused if using external runtime / data
148
148
startInlineScript : PrecomputedChunk ,
149
149
150
+ startInlineStyle : PrecomputedChunk ,
151
+
150
152
// the preamble must always flush before resuming, so all these chunks must
151
153
// be null or empty when resuming.
152
154
@@ -307,6 +309,8 @@ const scriptIntegirty = stringToPrecomputedChunk(' integrity="');
307
309
const scriptCrossOrigin = stringToPrecomputedChunk ( ' crossorigin="' ) ;
308
310
const endAsyncScript = stringToPrecomputedChunk ( ' async=""></script>' ) ;
309
311
312
+ const startInlineStyle = stringToPrecomputedChunk ( '<style' ) ;
313
+
310
314
/**
311
315
* This escaping function is designed to work with with inline scripts where the entire
312
316
* contents are escaped. Because we know we are escaping the entire script we can avoid for instance
@@ -365,17 +369,31 @@ if (__DEV__) {
365
369
// is set, the server will send instructions via data attributes (instead of inline scripts)
366
370
export function createRenderState (
367
371
resumableState : ResumableState ,
368
- nonce : string | void ,
372
+ nonce :
373
+ | string
374
+ | {
375
+ script ?: string ,
376
+ style ?: string ,
377
+ }
378
+ | void ,
369
379
externalRuntimeConfig : string | BootstrapScriptDescriptor | void ,
370
380
importMap : ImportMap | void ,
371
381
onHeaders : void | ( ( headers : HeadersDescriptor ) => void ) ,
372
382
maxHeadersLength : void | number ,
373
383
) : RenderState {
384
+ const nonceScript = typeof nonce === 'string' ? nonce : nonce && nonce . script ;
374
385
const inlineScriptWithNonce =
375
- nonce === undefined
386
+ nonceScript === undefined
376
387
? startInlineScript
377
388
: stringToPrecomputedChunk (
378
- '<script nonce="' + escapeTextForBrowser ( nonce ) + '"' ,
389
+ '<script nonce="' + escapeTextForBrowser ( nonceScript ) + '"' ,
390
+ ) ;
391
+ const nonceStyle = nonce && nonce . style ;
392
+ const inlineStyleWithNonce =
393
+ nonceStyle === undefined
394
+ ? startInlineStyle
395
+ : stringToPrecomputedChunk (
396
+ '<style nonce="' + escapeTextForBrowser ( nonceStyle ) + '"' ,
379
397
) ;
380
398
const idPrefix = resumableState . idPrefix ;
381
399
@@ -403,7 +421,7 @@ export function createRenderState(
403
421
src : externalRuntimeConfig ,
404
422
async : true ,
405
423
integrity : undefined ,
406
- nonce : nonce ,
424
+ nonce : nonceScript ,
407
425
} ) ;
408
426
} else {
409
427
externalRuntimeScript = {
@@ -414,7 +432,7 @@ export function createRenderState(
414
432
src : externalRuntimeConfig . src ,
415
433
async : true ,
416
434
integrity : externalRuntimeConfig . integrity ,
417
- nonce : nonce ,
435
+ nonce : nonceScript ,
418
436
} ) ;
419
437
}
420
438
}
@@ -459,6 +477,7 @@ export function createRenderState(
459
477
segmentPrefix : stringToPrecomputedChunk ( idPrefix + 'S:' ) ,
460
478
boundaryPrefix : stringToPrecomputedChunk ( idPrefix + 'B:' ) ,
461
479
startInlineScript : inlineScriptWithNonce ,
480
+ startInlineStyle : inlineStyleWithNonce ,
462
481
preamble : createPreambleState ( ) ,
463
482
464
483
externalRuntimeScript : externalRuntimeScript ,
@@ -500,7 +519,10 @@ export function createRenderState(
500
519
moduleScripts : new Map ( ) ,
501
520
} ,
502
521
503
- nonce,
522
+ nonce : {
523
+ script : nonceScript ,
524
+ style : nonceStyle ,
525
+ } ,
504
526
// like a module global for currently rendering boundary
505
527
hoistableState : null ,
506
528
stylesToHoist : false ,
@@ -539,10 +561,10 @@ export function createRenderState(
539
561
stringToChunk ( escapeTextForBrowser ( src ) ) ,
540
562
attributeEnd ,
541
563
) ;
542
- if ( nonce ) {
564
+ if ( nonceScript ) {
543
565
bootstrapChunks . push (
544
566
scriptNonce ,
545
- stringToChunk ( escapeTextForBrowser ( nonce ) ) ,
567
+ stringToChunk ( escapeTextForBrowser ( nonceScript ) ) ,
546
568
attributeEnd ,
547
569
) ;
548
570
}
@@ -571,7 +593,7 @@ export function createRenderState(
571
593
const props : PreloadModuleProps = ( {
572
594
rel : 'modulepreload' ,
573
595
fetchPriority : 'low' ,
574
- nonce,
596
+ nonce : nonceScript ,
575
597
} : any ) ;
576
598
if ( typeof scriptConfig === 'string' ) {
577
599
props . href = src = scriptConfig ;
@@ -596,10 +618,10 @@ export function createRenderState(
596
618
stringToChunk ( escapeTextForBrowser ( src ) ) ,
597
619
attributeEnd ,
598
620
) ;
599
- if ( nonce ) {
621
+ if ( nonceScript ) {
600
622
bootstrapChunks . push (
601
623
scriptNonce ,
602
- stringToChunk ( escapeTextForBrowser ( nonce ) ) ,
624
+ stringToChunk ( escapeTextForBrowser ( nonceScript ) ) ,
603
625
attributeEnd ,
604
626
) ;
605
627
}
@@ -2882,11 +2904,11 @@ function pushLink(
2882
2904
// to create a StyleQueue
2883
2905
if ( ! styleQueue ) {
2884
2906
styleQueue = {
2907
+ start : renderState . startInlineStyle ,
2885
2908
precedence : stringToChunk ( escapeTextForBrowser ( precedence ) ) ,
2886
2909
rules : ( [ ] : Array < Chunk | PrecomputedChunk > ) ,
2887
2910
hrefs : ( [ ] : Array < Chunk | PrecomputedChunk > ) ,
2888
2911
sheets : ( new Map ( ) : Map < string , StylesheetResource > ) ,
2889
- nonce : props . nonce ,
2890
2912
} ;
2891
2913
renderState . styles . set ( precedence , styleQueue ) ;
2892
2914
}
@@ -3091,21 +3113,29 @@ function pushStyle(
3091
3113
// This is the first time we've encountered this precedence we need
3092
3114
// to create a StyleQueue.
3093
3115
styleQueue = {
3116
+ start : renderState . startInlineStyle ,
3094
3117
precedence : stringToChunk ( escapeTextForBrowser ( precedence ) ) ,
3095
- rules : pushStyleContents ( ( [ ] : Array < Chunk | PrecomputedChunk > ) , props ) ,
3096
- hrefs : [ stringToChunk ( escapeTextForBrowser ( href ) ) ] ,
3118
+ rules : ( [ ] : Array < Chunk | PrecomputedChunk > ) ,
3119
+ hrefs : ( [ ] : Array < Chunk | PrecomputedChunk > ) ,
3097
3120
sheets : ( new Map ( ) : Map < string , StylesheetResource > ) ,
3098
- nonce : nonce ,
3099
3121
} ;
3100
3122
renderState . styles . set ( precedence , styleQueue ) ;
3101
- } else if ( nonce === styleQueue . nonce ) {
3102
- // We have seen this precedence before and need to track this href
3123
+ }
3124
+
3125
+ const nonceStyle = renderState . nonce . style ;
3126
+ if ( nonceStyle ? nonceStyle === nonce : ! nonce ) {
3103
3127
styleQueue . hrefs . push ( stringToChunk ( escapeTextForBrowser ( href ) ) ) ;
3104
3128
pushStyleContents ( styleQueue . rules , props ) ;
3105
3129
} else if ( __DEV__ ) {
3106
- console . error (
3107
- "React encountered a hoistable style tag with nonce. It doesn't match the previously encountered nonce. They have to be the same" ,
3108
- ) ;
3130
+ if ( nonceStyle ) {
3131
+ console . error (
3132
+ "React encountered a hoistable style tag with nonce. It doesn't match the previously encountered nonce. They have to be the same." ,
3133
+ ) ;
3134
+ } else {
3135
+ console . error (
3136
+ 'React encountered a hoistable style tag with nonce. The nonce was not passed to the render call though.' ,
3137
+ ) ;
3138
+ }
3109
3139
}
3110
3140
}
3111
3141
if ( styleQueue ) {
@@ -3198,7 +3228,7 @@ function pushStyleImpl(
3198
3228
function pushStyleContents (
3199
3229
target : Array < Chunk | PrecomputedChunk > ,
3200
3230
props : Object ,
3201
- ) : Array < Chunk | PrecomputedChunk > {
3231
+ ) : void {
3202
3232
let children = null ;
3203
3233
let innerHTML = null ;
3204
3234
for ( const propKey in props ) {
@@ -3232,7 +3262,7 @@ function pushStyleContents(
3232
3262
target . push ( stringToChunk ( escapeStyleTextContent ( child ) ) ) ;
3233
3263
}
3234
3264
pushInnerHTML ( target , innerHTML , children ) ;
3235
- return target ;
3265
+ return ;
3236
3266
}
3237
3267
3238
3268
function pushImg (
@@ -5155,11 +5185,10 @@ function escapeJSObjectForInstructionScripts(input: Object): string {
5155
5185
}
5156
5186
5157
5187
const lateStyleTagResourceOpen1 = stringToPrecomputedChunk (
5158
- '<style media="not all" data-precedence="' ,
5188
+ ' media="not all" data-precedence="' ,
5159
5189
) ;
5160
- const lateStyleTagResourceOpen2 = stringToPrecomputedChunk ( '" nonce="' ) ;
5161
- const lateStyleTagResourceOpen3 = stringToPrecomputedChunk ( '" data-href="' ) ;
5162
- const lateStyleTagResourceOpen4 = stringToPrecomputedChunk ( '">' ) ;
5190
+ const lateStyleTagResourceOpen2 = stringToPrecomputedChunk ( '" data-href="' ) ;
5191
+ const lateStyleTagResourceOpen3 = stringToPrecomputedChunk ( '">' ) ;
5163
5192
const lateStyleTagTemplateClose = stringToPrecomputedChunk ( '</style>' ) ;
5164
5193
5165
5194
// Tracks whether the boundary currently flushing is flushign style tags or has any
@@ -5175,7 +5204,6 @@ function flushStyleTagsLateForBoundary(
5175
5204
) {
5176
5205
const rules = styleQueue . rules ;
5177
5206
const hrefs = styleQueue . hrefs ;
5178
- const nonce = styleQueue . nonce ;
5179
5207
if ( __DEV__ ) {
5180
5208
if ( rules . length > 0 && hrefs . length === 0 ) {
5181
5209
console . error (
@@ -5185,19 +5213,16 @@ function flushStyleTagsLateForBoundary(
5185
5213
}
5186
5214
let i = 0 ;
5187
5215
if ( hrefs . length ) {
5216
+ writeChunk ( this , styleQueue . start ) ;
5188
5217
writeChunk ( this , lateStyleTagResourceOpen1 ) ;
5189
5218
writeChunk ( this , styleQueue . precedence ) ;
5190
- if ( nonce ) {
5191
- writeChunk ( this , lateStyleTagResourceOpen2 ) ;
5192
- writeChunk ( this , stringToChunk ( escapeTextForBrowser ( nonce ) ) ) ;
5193
- }
5194
- writeChunk ( this , lateStyleTagResourceOpen3 ) ;
5219
+ writeChunk ( this , lateStyleTagResourceOpen2 ) ;
5195
5220
for ( ; i < hrefs . length - 1 ; i ++ ) {
5196
5221
writeChunk ( this , hrefs [ i ] ) ;
5197
5222
writeChunk ( this , spaceSeparator ) ;
5198
5223
}
5199
5224
writeChunk ( this , hrefs [ i ] ) ;
5200
- writeChunk ( this , lateStyleTagResourceOpen4 ) ;
5225
+ writeChunk ( this , lateStyleTagResourceOpen3 ) ;
5201
5226
for ( i = 0 ; i < rules . length ; i ++ ) {
5202
5227
writeChunk ( this , rules [ i ] ) ;
5203
5228
}
@@ -5281,13 +5306,10 @@ function flushStyleInPreamble(
5281
5306
stylesheet . state = PREAMBLE ;
5282
5307
}
5283
5308
5284
- const styleTagResourceOpen1 = stringToPrecomputedChunk (
5285
- '<style data-precedence="' ,
5286
- ) ;
5287
- const styleTagResourceOpen2 = stringToPrecomputedChunk ( '" nonce="' ) ;
5288
- const styleTagResourceOpen3 = stringToPrecomputedChunk ( '" data-href="' ) ;
5309
+ const styleTagResourceOpen1 = stringToPrecomputedChunk ( ' data-precedence="' ) ;
5310
+ const styleTagResourceOpen2 = stringToPrecomputedChunk ( '" data-href="' ) ;
5289
5311
const spaceSeparator = stringToPrecomputedChunk ( ' ' ) ;
5290
- const styleTagResourceOpen4 = stringToPrecomputedChunk ( '">' ) ;
5312
+ const styleTagResourceOpen3 = stringToPrecomputedChunk ( '">' ) ;
5291
5313
5292
5314
const styleTagResourceClose = stringToPrecomputedChunk ( '</style>' ) ;
5293
5315
@@ -5302,27 +5324,23 @@ function flushStylesInPreamble(
5302
5324
5303
5325
const rules = styleQueue . rules ;
5304
5326
const hrefs = styleQueue . hrefs ;
5305
- const nonce = styleQueue . nonce ;
5306
5327
// If we don't emit any stylesheets at this precedence we still need to maintain the precedence
5307
5328
// order so even if there are no rules for style tags at this precedence we emit an empty style
5308
5329
// tag with the data-precedence attribute
5309
5330
if ( ! hasStylesheets || hrefs . length ) {
5331
+ writeChunk ( this , styleQueue . start ) ;
5310
5332
writeChunk ( this , styleTagResourceOpen1 ) ;
5311
5333
writeChunk ( this , styleQueue . precedence ) ;
5312
- if ( nonce ) {
5313
- writeChunk ( this , styleTagResourceOpen2 ) ;
5314
- writeChunk ( this , stringToChunk ( escapeTextForBrowser ( nonce ) ) ) ;
5315
- }
5316
5334
let i = 0 ;
5317
5335
if ( hrefs . length ) {
5318
- writeChunk ( this , styleTagResourceOpen3 ) ;
5336
+ writeChunk ( this , styleTagResourceOpen2 ) ;
5319
5337
for ( ; i < hrefs . length - 1 ; i ++ ) {
5320
5338
writeChunk ( this , hrefs [ i ] ) ;
5321
5339
writeChunk ( this , spaceSeparator ) ;
5322
5340
}
5323
5341
writeChunk ( this , hrefs [ i ] ) ;
5324
5342
}
5325
- writeChunk ( this , styleTagResourceOpen4 ) ;
5343
+ writeChunk ( this , styleTagResourceOpen3 ) ;
5326
5344
for ( i = 0 ; i < rules . length ; i ++ ) {
5327
5345
writeChunk ( this , rules [ i ] ) ;
5328
5346
}
@@ -6076,11 +6094,11 @@ export type HoistableState = {
6076
6094
} ;
6077
6095
6078
6096
export type StyleQueue = {
6097
+ start : PrecomputedChunk ,
6079
6098
precedence : Chunk | PrecomputedChunk ,
6080
6099
rules : Array < Chunk | PrecomputedChunk > ,
6081
6100
hrefs : Array < Chunk | PrecomputedChunk > ,
6082
6101
sheets : Map < string , StylesheetResource> ,
6083
- nonce : ?string ,
6084
6102
} ;
6085
6103
6086
6104
export function createHoistableState ( ) : HoistableState {
@@ -6528,11 +6546,11 @@ function preinitStyle(
6528
6546
// to create a StyleQueue
6529
6547
if ( ! styleQueue ) {
6530
6548
styleQueue = {
6549
+ start : renderState . startInlineStyle ,
6531
6550
precedence : stringToChunk ( escapeTextForBrowser ( precedence ) ) ,
6532
6551
rules : ( [ ] : Array < Chunk | PrecomputedChunk > ) ,
6533
6552
hrefs : ( [ ] : Array < Chunk | PrecomputedChunk > ) ,
6534
6553
sheets : ( new Map ( ) : Map < string , StylesheetResource > ) ,
6535
- nonce : options ? options . nonce : undefined ,
6536
6554
} ;
6537
6555
renderState . styles . set ( precedence , styleQueue ) ;
6538
6556
}
0 commit comments