Allow `nonce` to be used on hoistable styles (#32461)
fixes https://github.com/facebook/react/issues/32449 This is my first time touching this code. There are multiple systems in place here and I wouldn't be surprised to learn that this has to be handled in some other areas too. I have found some other style-related code areas but I had no time yet to double-check them. cc @gnoff
Mateusz Burzyński committed
May 29, 2025 at 17:17 UTC
14094f80cbf52cad4024211080d8491f3334ef61
11 files changed
+398
-30
packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js
+86
-20
@@ -135,6 +135,13 @@ const SentMarkShellTime /* */ = 0b001000000;
135
const NeedUpgradeToViewTransitions /* */ = 0b010000000;
136
const SentUpgradeToViewTransitions /* */ = 0b100000000;
137
138
+type NonceOption =
139
+ | string
140
+ | {
141
+ script?: string,
142
+ style?: string,
143
+ };
144
+
145
// Per request, global state that is not contextual to the rendering subtree.
146
// This cannot be resumed and therefore should only contain things that are
147
// temporary working state or are never used in the prerender pass.
@@ -147,6 +154,8 @@ export type RenderState = {
154
// inline script streaming format, unused if using external runtime / data
155
startInlineScript: PrecomputedChunk,
156
157
+ startInlineStyle: PrecomputedChunk,
158
+
159
// the preamble must always flush before resuming, so all these chunks must
160
// be null or empty when resuming.
161
@@ -209,6 +218,11 @@ export type RenderState = {
218
moduleScripts: Map<string, Resource>,
219
},
220
221
+ nonce: {
222
+ script: string | void,
223
+ style: string | void,
224
+ },
225
+
226
// Module-global-like reference for flushing/hoisting state of style resources
227
// We need to track whether the current request has flushed any style resources
228
// without sending an instruction to hoist them. we do that here
@@ -295,6 +309,8 @@ export type ResumableState = {
309
},
310
};
311
312
+let currentlyFlushingRenderState: RenderState | null = null;
313
+
314
const dataElementQuotedEnd = stringToPrecomputedChunk('"></template>');
315
316
const startInlineScript = stringToPrecomputedChunk('<script');
@@ -307,6 +323,8 @@ const scriptIntegirty = stringToPrecomputedChunk(' integrity="');
323
const scriptCrossOrigin = stringToPrecomputedChunk(' crossorigin="');
324
const endAsyncScript = stringToPrecomputedChunk(' async=""></script>');
325
326
+const startInlineStyle = stringToPrecomputedChunk('<style');
327
+
328
/**
329
* This escaping function is designed to work with with inline scripts where the entire
330
* contents are escaped. Because we know we are escaping the entire script we can avoid for instance
@@ -365,17 +383,32 @@ if (__DEV__) {
383
// is set, the server will send instructions via data attributes (instead of inline scripts)
384
export function createRenderState(
385
resumableState: ResumableState,
368
- nonce: string | void,
386
+ nonce:
387
+ | string
388
+ | {
389
+ script?: string,
390
+ style?: string,
391
+ }
392
+ | void,
393
externalRuntimeConfig: string | BootstrapScriptDescriptor | void,
394
importMap: ImportMap | void,
395
onHeaders: void | ((headers: HeadersDescriptor) => void),
396
maxHeadersLength: void | number,
397
): RenderState {
398
+ const nonceScript = typeof nonce === 'string' ? nonce : nonce && nonce.script;
399
const inlineScriptWithNonce =
375
- nonce === undefined
400
+ nonceScript === undefined
401
? startInlineScript
402
: stringToPrecomputedChunk(
378
- '<script nonce="' + escapeTextForBrowser(nonce) + '"',
403
+ '<script nonce="' + escapeTextForBrowser(nonceScript) + '"',
404
+ );
405
+ const nonceStyle =
406
+ typeof nonce === 'string' ? undefined : nonce && nonce.style;
407
+ const inlineStyleWithNonce =
408
+ nonceStyle === undefined
409
+ ? startInlineStyle
410
+ : stringToPrecomputedChunk(
411
+ '<style nonce="' + escapeTextForBrowser(nonceStyle) + '"',
412
);
413
const idPrefix = resumableState.idPrefix;
414
@@ -403,7 +436,7 @@ export function createRenderState(
436
src: externalRuntimeConfig,
437
async: true,
438
integrity: undefined,
406
- nonce: nonce,
439
+ nonce: nonceScript,
440
});
441
} else {
442
externalRuntimeScript = {
@@ -414,7 +447,7 @@ export function createRenderState(
447
src: externalRuntimeConfig.src,
448
async: true,
449
integrity: externalRuntimeConfig.integrity,
417
- nonce: nonce,
450
+ nonce: nonceScript,
451
});
452
}
453
}
@@ -459,6 +492,7 @@ export function createRenderState(
492
segmentPrefix: stringToPrecomputedChunk(idPrefix + 'S:'),
493
boundaryPrefix: stringToPrecomputedChunk(idPrefix + 'B:'),
494
startInlineScript: inlineScriptWithNonce,
495
+ startInlineStyle: inlineStyleWithNonce,
496
preamble: createPreambleState(),
497
498
externalRuntimeScript: externalRuntimeScript,
@@ -500,7 +534,10 @@ export function createRenderState(
534
moduleScripts: new Map(),
535
},
536
503
- nonce,
537
+ nonce: {
538
+ script: nonceScript,
539
+ style: nonceStyle,
540
+ },
541
// like a module global for currently rendering boundary
542
hoistableState: null,
543
stylesToHoist: false,
@@ -539,10 +576,10 @@ export function createRenderState(
576
stringToChunk(escapeTextForBrowser(src)),
577
attributeEnd,
578
);
542
- if (nonce) {
579
+ if (nonceScript) {
580
bootstrapChunks.push(
581
scriptNonce,
545
- stringToChunk(escapeTextForBrowser(nonce)),
582
+ stringToChunk(escapeTextForBrowser(nonceScript)),
583
attributeEnd,
584
);
585
}
@@ -571,7 +608,7 @@ export function createRenderState(
608
const props: PreloadModuleProps = ({
609
rel: 'modulepreload',
610
fetchPriority: 'low',
574
- nonce,
611
+ nonce: nonceScript,
612
}: any);
613
if (typeof scriptConfig === 'string') {
614
props.href = src = scriptConfig;
@@ -596,10 +633,10 @@ export function createRenderState(
633
stringToChunk(escapeTextForBrowser(src)),
634
attributeEnd,
635
);
599
- if (nonce) {
636
+ if (nonceScript) {
637
bootstrapChunks.push(
638
scriptNonce,
602
- stringToChunk(escapeTextForBrowser(nonce)),
639
+ stringToChunk(escapeTextForBrowser(nonceScript)),
640
attributeEnd,
641
);
642
}
@@ -627,7 +664,7 @@ export function createRenderState(
664
665
export function resumeRenderState(
666
resumableState: ResumableState,
630
- nonce: string | void,
667
+ nonce: NonceOption | void,
668
): RenderState {
669
return createRenderState(
670
resumableState,
@@ -3046,6 +3083,7 @@ function pushStyle(
3083
}
3084
const precedence = props.precedence;
3085
const href = props.href;
3086
+ const nonce = props.nonce;
3087
3088
if (
3089
formatContext.insertionMode === SVG_MODE ||
@@ -3091,15 +3129,33 @@ function pushStyle(
3129
styleQueue = {
3130
precedence: stringToChunk(escapeTextForBrowser(precedence)),
3131
rules: ([]: Array<Chunk | PrecomputedChunk>),
3094
- hrefs: [stringToChunk(escapeTextForBrowser(href))],
3132
+ hrefs: ([]: Array<Chunk | PrecomputedChunk>),
3133
sheets: (new Map(): Map<string, StylesheetResource>),
3134
};
3135
renderState.styles.set(precedence, styleQueue);
3098
- } else {
3099
- // We have seen this precedence before and need to track this href
3136
+ }
3137
+
3138
+ const nonceStyle = renderState.nonce.style;
3139
+ if (!nonceStyle || nonceStyle === nonce) {
3140
+ if (__DEV__) {
3141
+ if (!nonceStyle && nonce) {
3142
+ console.error(
3143
+ 'React encountered a style tag with `precedence` "%s" and `nonce` "%s". When React manages style rules using `precedence` it will only include a nonce attributes if you also provide the same style nonce value as a render option.',
3144
+ precedence,
3145
+ nonce,
3146
+ );
3147
+ }
3148
+ }
3149
styleQueue.hrefs.push(stringToChunk(escapeTextForBrowser(href)));
3150
+ pushStyleContents(styleQueue.rules, props);
3151
+ } else if (__DEV__) {
3152
+ console.error(
3153
+ 'React encountered a style tag with `precedence` "%s" and `nonce` "%s". When React manages style rules using `precedence` it will only include rules if the nonce matches the style nonce "%s" that was included with this render.',
3154
+ precedence,
3155
+ nonce,
3156
+ nonceStyle,
3157
+ );
3158
}
3102
- pushStyleContents(styleQueue.rules, props);
3159
}
3160
if (styleQueue) {
3161
// We need to track whether this boundary should wait on this resource or not.
@@ -5148,7 +5204,7 @@ function escapeJSObjectForInstructionScripts(input: Object): string {
5204
}
5205
5206
const lateStyleTagResourceOpen1 = stringToPrecomputedChunk(
5151
- '<style media="not all" data-precedence="',
5207
+ ' media="not all" data-precedence="',
5208
);
5209
const lateStyleTagResourceOpen2 = stringToPrecomputedChunk('" data-href="');
5210
const lateStyleTagResourceOpen3 = stringToPrecomputedChunk('">');
@@ -5176,6 +5232,10 @@ function flushStyleTagsLateForBoundary(
5232
}
5233
let i = 0;
5234
if (hrefs.length) {
5235
+ writeChunk(
5236
+ this,
5237
+ ((currentlyFlushingRenderState: any): RenderState).startInlineStyle,
5238
+ );
5239
writeChunk(this, lateStyleTagResourceOpen1);
5240
writeChunk(this, styleQueue.precedence);
5241
writeChunk(this, lateStyleTagResourceOpen2);
@@ -5225,7 +5285,9 @@ export function writeHoistablesForBoundary(
5285
destinationHasCapacity = true;
5286
5287
// Flush style tags for each precedence this boundary depends on
5288
+ currentlyFlushingRenderState = renderState;
5289
hoistableState.styles.forEach(flushStyleTagsLateForBoundary, destination);
5290
+ currentlyFlushingRenderState = null;
5291
5292
// Determine if this boundary has stylesheets that need to be awaited upon completion
5293
hoistableState.stylesheets.forEach(hasStylesToHoist);
@@ -5268,9 +5330,7 @@ function flushStyleInPreamble(
5330
stylesheet.state = PREAMBLE;
5331
}
5332
5271
-const styleTagResourceOpen1 = stringToPrecomputedChunk(
5272
- '<style data-precedence="',
5273
-);
5333
+const styleTagResourceOpen1 = stringToPrecomputedChunk(' data-precedence="');
5334
const styleTagResourceOpen2 = stringToPrecomputedChunk('" data-href="');
5335
const spaceSeparator = stringToPrecomputedChunk(' ');
5336
const styleTagResourceOpen3 = stringToPrecomputedChunk('">');
@@ -5292,6 +5352,10 @@ function flushStylesInPreamble(
5352
// order so even if there are no rules for style tags at this precedence we emit an empty style
5353
// tag with the data-precedence attribute
5354
if (!hasStylesheets || hrefs.length) {
5355
+ writeChunk(
5356
+ this,
5357
+ ((currentlyFlushingRenderState: any): RenderState).startInlineStyle,
5358
+ );
5359
writeChunk(this, styleTagResourceOpen1);
5360
writeChunk(this, styleQueue.precedence);
5361
let i = 0;
@@ -5466,7 +5530,9 @@ export function writePreambleStart(
5530
renderState.highImagePreloads.clear();
5531
5532
// Flush unblocked stylesheets by precedence
5533
+ currentlyFlushingRenderState = renderState;
5534
renderState.styles.forEach(flushStylesInPreamble, destination);
5535
+ currentlyFlushingRenderState = null;
5536
5537
const importMapChunks = renderState.importMapChunks;
5538
for (i = 0; i < importMapChunks.length; i++) {
packages/react-dom-bindings/src/server/ReactFizzConfigDOMLegacy.js
+7
@@ -47,6 +47,7 @@ export type RenderState = {
47
segmentPrefix: PrecomputedChunk,
48
boundaryPrefix: PrecomputedChunk,
49
startInlineScript: PrecomputedChunk,
50
+ startInlineStyle: PrecomputedChunk,
51
preamble: PreambleState,
52
externalRuntimeScript: null | any,
53
bootstrapChunks: Array<Chunk | PrecomputedChunk>,
@@ -76,6 +77,10 @@ export type RenderState = {
77
scripts: Map<string, Resource>,
78
moduleScripts: Map<string, Resource>,
79
},
80
+ nonce: {
81
+ script: string | void,
82
+ style: string | void,
83
+ },
84
stylesToHoist: boolean,
85
// This is an extra field for the legacy renderer
86
generateStaticMarkup: boolean,
@@ -99,6 +104,7 @@ export function createRenderState(
104
segmentPrefix: renderState.segmentPrefix,
105
boundaryPrefix: renderState.boundaryPrefix,
106
startInlineScript: renderState.startInlineScript,
107
+ startInlineStyle: renderState.startInlineStyle,
108
preamble: renderState.preamble,
109
externalRuntimeScript: renderState.externalRuntimeScript,
110
bootstrapChunks: renderState.bootstrapChunks,
@@ -118,6 +124,7 @@ export function createRenderState(
124
scripts: renderState.scripts,
125
bulkPreloads: renderState.bulkPreloads,
126
preloads: renderState.preloads,
127
+ nonce: renderState.nonce,
128
stylesToHoist: renderState.stylesToHoist,
129
130
// This is an extra field for the legacy renderer
packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
+168
@@ -10279,4 +10279,172 @@ describe('ReactDOMFizzServer', () => {
10279
</html>,
10280
);
10281
});
10282
+
10283
+ it('can render styles with nonce', async () => {
10284
+ CSPnonce = 'R4nd0m';
10285
+ await act(() => {
10286
+ const {pipe} = renderToPipeableStream(
10287
+ <>
10288
+ <style
10289
+ href="foo"
10290
+ precedence="default"
10291
+ nonce={CSPnonce}>{`.foo { color: hotpink; }`}</style>
10292
+ <style
10293
+ href="bar"
10294
+ precedence="default"
10295
+ nonce={CSPnonce}>{`.bar { background-color: blue; }`}</style>
10296
+ </>,
10297
+ {nonce: {style: CSPnonce}},
10298
+ );
10299
+ pipe(writable);
10300
+ });
10301
+ expect(document.querySelector('style').nonce).toBe(CSPnonce);
10302
+ expect(getVisibleChildren(document)).toEqual(
10303
+ <html>
10304
+ <head />
10305
+ <body>
10306
+ <div id="container">
10307
+ <style
10308
+ data-precedence="default"
10309
+ data-href="foo bar"
10310
+ nonce={
10311
+ CSPnonce
10312
+ }>{`.foo { color: hotpink; }.bar { background-color: blue; }`}</style>
10313
+ </div>
10314
+ </body>
10315
+ </html>,
10316
+ );
10317
+ });
10318
+
10319
+ it("shouldn't render styles with mismatched nonce", async () => {
10320
+ CSPnonce = 'R4nd0m';
10321
+ await act(() => {
10322
+ const {pipe} = renderToPipeableStream(
10323
+ <>
10324
+ <style
10325
+ href="foo"
10326
+ precedence="default"
10327
+ nonce={CSPnonce}>{`.foo { color: hotpink; }`}</style>
10328
+ <style
10329
+ href="bar"
10330
+ precedence="default"
10331
+ nonce={`${CSPnonce}${CSPnonce}`}>{`.bar { background-color: blue; }`}</style>
10332
+ </>,
10333
+ {nonce: {style: CSPnonce}},
10334
+ );
10335
+ pipe(writable);
10336
+ });
10337
+ assertConsoleErrorDev([
10338
+ 'React encountered a style tag with `precedence` "default" and `nonce` "R4nd0mR4nd0m". When React manages style rules using `precedence` it will only include rules if the nonce matches the style nonce "R4nd0m" that was included with this render.',
10339
+ ]);
10340
+ expect(getVisibleChildren(document)).toEqual(
10341
+ <html>
10342
+ <head />
10343
+ <body>
10344
+ <div id="container">
10345
+ <style
10346
+ data-precedence="default"
10347
+ data-href="foo"
10348
+ nonce={CSPnonce}>{`.foo { color: hotpink; }`}</style>
10349
+ </div>
10350
+ </body>
10351
+ </html>,
10352
+ );
10353
+ });
10354
+
10355
+ it("should render styles without nonce when render call doesn't receive nonce", async () => {
10356
+ await act(() => {
10357
+ const {pipe} = renderToPipeableStream(
10358
+ <>
10359
+ <style
10360
+ href="foo"
10361
+ precedence="default"
10362
+ nonce="R4nd0m">{`.foo { color: hotpink; }`}</style>
10363
+ </>,
10364
+ );
10365
+ pipe(writable);
10366
+ });
10367
+ assertConsoleErrorDev([
10368
+ 'React encountered a style tag with `precedence` "default" and `nonce` "R4nd0m". When React manages style rules using `precedence` it will only include a nonce attributes if you also provide the same style nonce value as a render option.',
10369
+ ]);
10370
+ expect(getVisibleChildren(document)).toEqual(
10371
+ <html>
10372
+ <head />
10373
+ <body>
10374
+ <div id="container">
10375
+ <style
10376
+ data-precedence="default"
10377
+ data-href="foo">{`.foo { color: hotpink; }`}</style>
10378
+ </div>
10379
+ </body>
10380
+ </html>,
10381
+ );
10382
+ });
10383
+
10384
+ it('should render styles without nonce when render call receives a string nonce dedicated to scripts', async () => {
10385
+ CSPnonce = 'R4nd0m';
10386
+ await act(() => {
10387
+ const {pipe} = renderToPipeableStream(
10388
+ <>
10389
+ <style
10390
+ href="foo"
10391
+ precedence="default"
10392
+ nonce={CSPnonce}>{`.foo { color: hotpink; }`}</style>
10393
+ </>,
10394
+ {nonce: CSPnonce},
10395
+ );
10396
+ pipe(writable);
10397
+ });
10398
+ assertConsoleErrorDev([
10399
+ 'React encountered a style tag with `precedence` "default" and `nonce` "R4nd0m". When React manages style rules using `precedence` it will only include a nonce attributes if you also provide the same style nonce value as a render option.',
10400
+ ]);
10401
+ expect(getVisibleChildren(document)).toEqual(
10402
+ <html>
10403
+ <head />
10404
+ <body>
10405
+ <div id="container">
10406
+ <style
10407
+ data-precedence="default"
10408
+ data-href="foo">{`.foo { color: hotpink; }`}</style>
10409
+ </div>
10410
+ </body>
10411
+ </html>,
10412
+ );
10413
+ });
10414
+
10415
+ it('should allow for different script and style nonces', async () => {
10416
+ CSPnonce = 'R4nd0m';
10417
+ await act(() => {
10418
+ const {pipe} = renderToPipeableStream(
10419
+ <>
10420
+ <style
10421
+ href="foo"
10422
+ precedence="default"
10423
+ nonce="D1ff3r3nt">{`.foo { color: hotpink; }`}</style>
10424
+ </>,
10425
+ {
10426
+ nonce: {script: CSPnonce, style: 'D1ff3r3nt'},
10427
+ bootstrapScriptContent: 'function noop(){}',
10428
+ },
10429
+ );
10430
+ pipe(writable);
10431
+ });
10432
+ const scripts = Array.from(container.getElementsByTagName('script')).filter(
10433
+ node => node.getAttribute('nonce') === CSPnonce,
10434
+ );
10435
+ expect(scripts[scripts.length - 1].textContent).toBe('function noop(){}');
10436
+ expect(getVisibleChildren(document)).toEqual(
10437
+ <html>
10438
+ <head />
10439
+ <body>
10440
+ <div id="container">
10441
+ <style
10442
+ data-precedence="default"
10443
+ data-href="foo"
10444
+ nonce="D1ff3r3nt">{`.foo { color: hotpink; }`}</style>
10445
+ </div>
10446
+ </body>
10447
+ </html>,
10448
+ );
10449
+ });
10450
});
packages/react-dom/src/__tests__/ReactDOMFloat-test.js
+80
@@ -8595,6 +8595,86 @@ background-color: green;
8595
' in style (at **)',
8596
]);
8597
});
8598
+
8599
+ it('can emit styles with nonce', async () => {
8600
+ const nonce = 'R4nD0m';
8601
+ const fooCss = '.foo { color: hotpink; }';
8602
+ const barCss = '.bar { background-color: blue; }';
8603
+ const bazCss = '.baz { border: 1px solid black; }';
8604
+ await act(() => {
8605
+ renderToPipeableStream(
8606
+ <html>
8607
+ <body>
8608
+ <Suspense>
8609
+ <BlockedOn value="first">
8610
+ <div>first</div>
8611
+ <style href="foo" precedence="default" nonce={nonce}>
8612
+ {fooCss}
8613
+ </style>
8614
+ <style href="bar" precedence="default" nonce={nonce}>
8615
+ {barCss}
8616
+ </style>
8617
+ <BlockedOn value="second">
8618
+ <div>second</div>
8619
+ <style href="baz" precedence="default" nonce={nonce}>
8620
+ {bazCss}
8621
+ </style>
8622
+ </BlockedOn>
8623
+ </BlockedOn>
8624
+ </Suspense>
8625
+ </body>
8626
+ </html>,
8627
+ {nonce: {style: nonce}},
8628
+ ).pipe(writable);
8629
+ });
8630
+
8631
+ expect(getMeaningfulChildren(document)).toEqual(
8632
+ <html>
8633
+ <head />
8634
+ <body />
8635
+ </html>,
8636
+ );
8637
+
8638
+ await act(() => {
8639
+ resolveText('first');
8640
+ });
8641
+
8642
+ expect(getMeaningfulChildren(document)).toEqual(
8643
+ <html>
8644
+ <head />
8645
+ <body>
8646
+ <style
8647
+ data-href="foo bar"
8648
+ data-precedence="default"
8649
+ media="not all"
8650
+ nonce={nonce}>
8651
+ {`${fooCss}${barCss}`}
8652
+ </style>
8653
+ </body>
8654
+ </html>,
8655
+ );
8656
+
8657
+ await act(() => {
8658
+ resolveText('second');
8659
+ });
8660
+
8661
+ expect(getMeaningfulChildren(document)).toEqual(
8662
+ <html>
8663
+ <head>
8664
+ <style data-href="foo bar" data-precedence="default" nonce={nonce}>
8665
+ {`${fooCss}${barCss}`}
8666
+ </style>
8667
+ <style data-href="baz" data-precedence="default" nonce={nonce}>
8668
+ {bazCss}
8669
+ </style>
8670
+ </head>
8671
+ <body>
8672
+ <div>first</div>
8673
+ <div>second</div>
8674
+ </body>
8675
+ </html>,
8676
+ );
8677
+ });
8678
});
8679
8680
describe('Script Resources', () => {
packages/react-dom/src/server/ReactDOMFizzServerBrowser.js
+9
-2
@@ -40,10 +40,17 @@ import {
40
import {ensureCorrectIsomorphicReactVersion} from '../shared/ensureCorrectIsomorphicReactVersion';
41
ensureCorrectIsomorphicReactVersion();
42
43
+type NonceOption =
44
+ | string
45
+ | {
46
+ script?: string,
47
+ style?: string,
48
+ };
49
+
50
type Options = {
51
identifierPrefix?: string,
52
namespaceURI?: string,
46
- nonce?: string,
53
+ nonce?: NonceOption,
54
bootstrapScriptContent?: string,
55
bootstrapScripts?: Array<string | BootstrapScriptDescriptor>,
56
bootstrapModules?: Array<string | BootstrapScriptDescriptor>,
@@ -59,7 +66,7 @@ type Options = {
66
};
67
68
type ResumeOptions = {
62
- nonce?: string,
69
+ nonce?: NonceOption,
70
signal?: AbortSignal,
71
onError?: (error: mixed) => ?string,
72
onPostpone?: (reason: string) => void,
packages/react-dom/src/server/ReactDOMFizzServerBun.js
+6
-1
@@ -37,7 +37,12 @@ ensureCorrectIsomorphicReactVersion();
37
type Options = {
38
identifierPrefix?: string,
39
namespaceURI?: string,
40
- nonce?: string,
40
+ nonce?:
41
+ | string
42
+ | {
43
+ script?: string,
44
+ style?: string,
45
+ },
46
bootstrapScriptContent?: string,
47
bootstrapScripts?: Array<string | BootstrapScriptDescriptor>,
48
bootstrapModules?: Array<string | BootstrapScriptDescriptor>,
packages/react-dom/src/server/ReactDOMFizzServerEdge.js
+9
-2
@@ -40,10 +40,17 @@ import {
40
import {ensureCorrectIsomorphicReactVersion} from '../shared/ensureCorrectIsomorphicReactVersion';
41
ensureCorrectIsomorphicReactVersion();
42
43
+type NonceOption =
44
+ | string
45
+ | {
46
+ script?: string,
47
+ style?: string,
48
+ };
49
+
50
type Options = {
51
identifierPrefix?: string,
52
namespaceURI?: string,
46
- nonce?: string,
53
+ nonce?: NonceOption,
54
bootstrapScriptContent?: string,
55
bootstrapScripts?: Array<string | BootstrapScriptDescriptor>,
56
bootstrapModules?: Array<string | BootstrapScriptDescriptor>,
@@ -59,7 +66,7 @@ type Options = {
66
};
67
68
type ResumeOptions = {
62
- nonce?: string,
69
+ nonce?: NonceOption,
70
signal?: AbortSignal,
71
onError?: (error: mixed) => ?string,
72
onPostpone?: (reason: string) => void,
packages/react-dom/src/server/ReactDOMFizzServerNode.js
+9
-2
@@ -56,10 +56,17 @@ function createCancelHandler(request: Request, reason: string) {
56
};
57
}
58
59
+type NonceOption =
60
+ | string
61
+ | {
62
+ script?: string,
63
+ style?: string,
64
+ };
65
+
66
type Options = {
67
identifierPrefix?: string,
68
namespaceURI?: string,
62
- nonce?: string,
69
+ nonce?: NonceOption,
70
bootstrapScriptContent?: string,
71
bootstrapScripts?: Array<string | BootstrapScriptDescriptor>,
72
bootstrapModules?: Array<string | BootstrapScriptDescriptor>,
@@ -77,7 +84,7 @@ type Options = {
84
};
85
86
type ResumeOptions = {
80
- nonce?: string,
87
+ nonce?: NonceOption,
88
onShellReady?: () => void,
89
onShellError?: (error: mixed) => void,
90
onAllReady?: () => void,
packages/react-dom/src/server/ReactDOMFizzStaticBrowser.js
+8
-1
@@ -43,6 +43,13 @@ import {enablePostpone, enableHalt} from 'shared/ReactFeatureFlags';
43
import {ensureCorrectIsomorphicReactVersion} from '../shared/ensureCorrectIsomorphicReactVersion';
44
ensureCorrectIsomorphicReactVersion();
45
46
+type NonceOption =
47
+ | string
48
+ | {
49
+ script?: string,
50
+ style?: string,
51
+ };
52
+
53
type Options = {
54
identifierPrefix?: string,
55
namespaceURI?: string,
@@ -151,7 +158,7 @@ function prerender(
158
}
159
160
type ResumeOptions = {
154
- nonce?: string,
161
+ nonce?: NonceOption,
162
signal?: AbortSignal,
163
onError?: (error: mixed) => ?string,
164
onPostpone?: (reason: string) => void,
packages/react-dom/src/server/ReactDOMFizzStaticEdge.js
+8
-1
@@ -43,6 +43,13 @@ import {enablePostpone, enableHalt} from 'shared/ReactFeatureFlags';
43
import {ensureCorrectIsomorphicReactVersion} from '../shared/ensureCorrectIsomorphicReactVersion';
44
ensureCorrectIsomorphicReactVersion();
45
46
+type NonceOption =
47
+ | string
48
+ | {
49
+ script?: string,
50
+ style?: string,
51
+ };
52
+
53
type Options = {
54
identifierPrefix?: string,
55
namespaceURI?: string,
@@ -150,7 +157,7 @@ function prerender(
157
}
158
159
type ResumeOptions = {
153
- nonce?: string,
160
+ nonce?: NonceOption,
161
signal?: AbortSignal,
162
onError?: (error: mixed) => ?string,
163
onPostpone?: (reason: string) => void,
packages/react-dom/src/server/ReactDOMFizzStaticNode.js
+8
-1
@@ -44,6 +44,13 @@ import {enablePostpone, enableHalt} from 'shared/ReactFeatureFlags';
44
import {ensureCorrectIsomorphicReactVersion} from '../shared/ensureCorrectIsomorphicReactVersion';
45
ensureCorrectIsomorphicReactVersion();
46
47
+type NonceOption =
48
+ | string
49
+ | {
50
+ script?: string,
51
+ style?: string,
52
+ };
53
+
54
type Options = {
55
identifierPrefix?: string,
56
namespaceURI?: string,
@@ -151,7 +158,7 @@ function prerenderToNodeStream(
158
}
159
160
type ResumeOptions = {
154
- nonce?: string,
161
+ nonce?: NonceOption,
162
signal?: AbortSignal,
163
onError?: (error: mixed, errorInfo: ErrorInfo) => ?string,
164
onPostpone?: (reason: string, postponeInfo: PostponeInfo) => void,