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