Skip to content

Commit 6936609

Browse files
committed
Refactor
1 parent a3259a0 commit 6936609

File tree

8 files changed

+88
-53
lines changed

8 files changed

+88
-53
lines changed

packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js

Lines changed: 66 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ export type RenderState = {
147147
// inline script streaming format, unused if using external runtime / data
148148
startInlineScript: PrecomputedChunk,
149149

150+
startInlineStyle: PrecomputedChunk,
151+
150152
// the preamble must always flush before resuming, so all these chunks must
151153
// be null or empty when resuming.
152154

@@ -307,6 +309,8 @@ const scriptIntegirty = stringToPrecomputedChunk(' integrity="');
307309
const scriptCrossOrigin = stringToPrecomputedChunk(' crossorigin="');
308310
const endAsyncScript = stringToPrecomputedChunk(' async=""></script>');
309311

312+
const startInlineStyle = stringToPrecomputedChunk('<style');
313+
310314
/**
311315
* This escaping function is designed to work with with inline scripts where the entire
312316
* contents are escaped. Because we know we are escaping the entire script we can avoid for instance
@@ -365,17 +369,31 @@ if (__DEV__) {
365369
// is set, the server will send instructions via data attributes (instead of inline scripts)
366370
export function createRenderState(
367371
resumableState: ResumableState,
368-
nonce: string | void,
372+
nonce:
373+
| string
374+
| {
375+
script?: string,
376+
style?: string,
377+
}
378+
| void,
369379
externalRuntimeConfig: string | BootstrapScriptDescriptor | void,
370380
importMap: ImportMap | void,
371381
onHeaders: void | ((headers: HeadersDescriptor) => void),
372382
maxHeadersLength: void | number,
373383
): RenderState {
384+
const nonceScript = typeof nonce === 'string' ? nonce : nonce && nonce.script;
374385
const inlineScriptWithNonce =
375-
nonce === undefined
386+
nonceScript === undefined
376387
? startInlineScript
377388
: 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) + '"',
379397
);
380398
const idPrefix = resumableState.idPrefix;
381399

@@ -403,7 +421,7 @@ export function createRenderState(
403421
src: externalRuntimeConfig,
404422
async: true,
405423
integrity: undefined,
406-
nonce: nonce,
424+
nonce: nonceScript,
407425
});
408426
} else {
409427
externalRuntimeScript = {
@@ -414,7 +432,7 @@ export function createRenderState(
414432
src: externalRuntimeConfig.src,
415433
async: true,
416434
integrity: externalRuntimeConfig.integrity,
417-
nonce: nonce,
435+
nonce: nonceScript,
418436
});
419437
}
420438
}
@@ -459,6 +477,7 @@ export function createRenderState(
459477
segmentPrefix: stringToPrecomputedChunk(idPrefix + 'S:'),
460478
boundaryPrefix: stringToPrecomputedChunk(idPrefix + 'B:'),
461479
startInlineScript: inlineScriptWithNonce,
480+
startInlineStyle: inlineStyleWithNonce,
462481
preamble: createPreambleState(),
463482

464483
externalRuntimeScript: externalRuntimeScript,
@@ -500,7 +519,10 @@ export function createRenderState(
500519
moduleScripts: new Map(),
501520
},
502521

503-
nonce,
522+
nonce: {
523+
script: nonceScript,
524+
style: nonceStyle,
525+
},
504526
// like a module global for currently rendering boundary
505527
hoistableState: null,
506528
stylesToHoist: false,
@@ -539,10 +561,10 @@ export function createRenderState(
539561
stringToChunk(escapeTextForBrowser(src)),
540562
attributeEnd,
541563
);
542-
if (nonce) {
564+
if (nonceScript) {
543565
bootstrapChunks.push(
544566
scriptNonce,
545-
stringToChunk(escapeTextForBrowser(nonce)),
567+
stringToChunk(escapeTextForBrowser(nonceScript)),
546568
attributeEnd,
547569
);
548570
}
@@ -571,7 +593,7 @@ export function createRenderState(
571593
const props: PreloadModuleProps = ({
572594
rel: 'modulepreload',
573595
fetchPriority: 'low',
574-
nonce,
596+
nonce: nonceScript,
575597
}: any);
576598
if (typeof scriptConfig === 'string') {
577599
props.href = src = scriptConfig;
@@ -596,10 +618,10 @@ export function createRenderState(
596618
stringToChunk(escapeTextForBrowser(src)),
597619
attributeEnd,
598620
);
599-
if (nonce) {
621+
if (nonceScript) {
600622
bootstrapChunks.push(
601623
scriptNonce,
602-
stringToChunk(escapeTextForBrowser(nonce)),
624+
stringToChunk(escapeTextForBrowser(nonceScript)),
603625
attributeEnd,
604626
);
605627
}
@@ -2882,11 +2904,11 @@ function pushLink(
28822904
// to create a StyleQueue
28832905
if (!styleQueue) {
28842906
styleQueue = {
2907+
start: renderState.startInlineStyle,
28852908
precedence: stringToChunk(escapeTextForBrowser(precedence)),
28862909
rules: ([]: Array<Chunk | PrecomputedChunk>),
28872910
hrefs: ([]: Array<Chunk | PrecomputedChunk>),
28882911
sheets: (new Map(): Map<string, StylesheetResource>),
2889-
nonce: props.nonce,
28902912
};
28912913
renderState.styles.set(precedence, styleQueue);
28922914
}
@@ -3091,21 +3113,29 @@ function pushStyle(
30913113
// This is the first time we've encountered this precedence we need
30923114
// to create a StyleQueue.
30933115
styleQueue = {
3116+
start: renderState.startInlineStyle,
30943117
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>),
30973120
sheets: (new Map(): Map<string, StylesheetResource>),
3098-
nonce: nonce,
30993121
};
31003122
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) {
31033127
styleQueue.hrefs.push(stringToChunk(escapeTextForBrowser(href)));
31043128
pushStyleContents(styleQueue.rules, props);
31053129
} 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+
}
31093139
}
31103140
}
31113141
if (styleQueue) {
@@ -3198,7 +3228,7 @@ function pushStyleImpl(
31983228
function pushStyleContents(
31993229
target: Array<Chunk | PrecomputedChunk>,
32003230
props: Object,
3201-
): Array<Chunk | PrecomputedChunk> {
3231+
): void {
32023232
let children = null;
32033233
let innerHTML = null;
32043234
for (const propKey in props) {
@@ -3232,7 +3262,7 @@ function pushStyleContents(
32323262
target.push(stringToChunk(escapeStyleTextContent(child)));
32333263
}
32343264
pushInnerHTML(target, innerHTML, children);
3235-
return target;
3265+
return;
32363266
}
32373267

32383268
function pushImg(
@@ -5155,11 +5185,10 @@ function escapeJSObjectForInstructionScripts(input: Object): string {
51555185
}
51565186

51575187
const lateStyleTagResourceOpen1 = stringToPrecomputedChunk(
5158-
'<style media="not all" data-precedence="',
5188+
' media="not all" data-precedence="',
51595189
);
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('">');
51635192
const lateStyleTagTemplateClose = stringToPrecomputedChunk('</style>');
51645193

51655194
// Tracks whether the boundary currently flushing is flushign style tags or has any
@@ -5175,7 +5204,6 @@ function flushStyleTagsLateForBoundary(
51755204
) {
51765205
const rules = styleQueue.rules;
51775206
const hrefs = styleQueue.hrefs;
5178-
const nonce = styleQueue.nonce;
51795207
if (__DEV__) {
51805208
if (rules.length > 0 && hrefs.length === 0) {
51815209
console.error(
@@ -5185,19 +5213,16 @@ function flushStyleTagsLateForBoundary(
51855213
}
51865214
let i = 0;
51875215
if (hrefs.length) {
5216+
writeChunk(this, styleQueue.start);
51885217
writeChunk(this, lateStyleTagResourceOpen1);
51895218
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);
51955220
for (; i < hrefs.length - 1; i++) {
51965221
writeChunk(this, hrefs[i]);
51975222
writeChunk(this, spaceSeparator);
51985223
}
51995224
writeChunk(this, hrefs[i]);
5200-
writeChunk(this, lateStyleTagResourceOpen4);
5225+
writeChunk(this, lateStyleTagResourceOpen3);
52015226
for (i = 0; i < rules.length; i++) {
52025227
writeChunk(this, rules[i]);
52035228
}
@@ -5281,13 +5306,10 @@ function flushStyleInPreamble(
52815306
stylesheet.state = PREAMBLE;
52825307
}
52835308

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="');
52895311
const spaceSeparator = stringToPrecomputedChunk(' ');
5290-
const styleTagResourceOpen4 = stringToPrecomputedChunk('">');
5312+
const styleTagResourceOpen3 = stringToPrecomputedChunk('">');
52915313

52925314
const styleTagResourceClose = stringToPrecomputedChunk('</style>');
52935315

@@ -5302,27 +5324,23 @@ function flushStylesInPreamble(
53025324

53035325
const rules = styleQueue.rules;
53045326
const hrefs = styleQueue.hrefs;
5305-
const nonce = styleQueue.nonce;
53065327
// If we don't emit any stylesheets at this precedence we still need to maintain the precedence
53075328
// order so even if there are no rules for style tags at this precedence we emit an empty style
53085329
// tag with the data-precedence attribute
53095330
if (!hasStylesheets || hrefs.length) {
5331+
writeChunk(this, styleQueue.start);
53105332
writeChunk(this, styleTagResourceOpen1);
53115333
writeChunk(this, styleQueue.precedence);
5312-
if (nonce) {
5313-
writeChunk(this, styleTagResourceOpen2);
5314-
writeChunk(this, stringToChunk(escapeTextForBrowser(nonce)));
5315-
}
53165334
let i = 0;
53175335
if (hrefs.length) {
5318-
writeChunk(this, styleTagResourceOpen3);
5336+
writeChunk(this, styleTagResourceOpen2);
53195337
for (; i < hrefs.length - 1; i++) {
53205338
writeChunk(this, hrefs[i]);
53215339
writeChunk(this, spaceSeparator);
53225340
}
53235341
writeChunk(this, hrefs[i]);
53245342
}
5325-
writeChunk(this, styleTagResourceOpen4);
5343+
writeChunk(this, styleTagResourceOpen3);
53265344
for (i = 0; i < rules.length; i++) {
53275345
writeChunk(this, rules[i]);
53285346
}
@@ -6076,11 +6094,11 @@ export type HoistableState = {
60766094
};
60776095

60786096
export type StyleQueue = {
6097+
start: PrecomputedChunk,
60796098
precedence: Chunk | PrecomputedChunk,
60806099
rules: Array<Chunk | PrecomputedChunk>,
60816100
hrefs: Array<Chunk | PrecomputedChunk>,
60826101
sheets: Map<string, StylesheetResource>,
6083-
nonce: ?string,
60846102
};
60856103

60866104
export function createHoistableState(): HoistableState {
@@ -6528,11 +6546,11 @@ function preinitStyle(
65286546
// to create a StyleQueue
65296547
if (!styleQueue) {
65306548
styleQueue = {
6549+
start: renderState.startInlineStyle,
65316550
precedence: stringToChunk(escapeTextForBrowser(precedence)),
65326551
rules: ([]: Array<Chunk | PrecomputedChunk>),
65336552
hrefs: ([]: Array<Chunk | PrecomputedChunk>),
65346553
sheets: (new Map(): Map<string, StylesheetResource>),
6535-
nonce: options ? options.nonce : undefined,
65366554
};
65376555
renderState.styles.set(precedence, styleQueue);
65386556
}

packages/react-dom-bindings/src/server/ReactFizzConfigDOMLegacy.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export type RenderState = {
4747
segmentPrefix: PrecomputedChunk,
4848
boundaryPrefix: PrecomputedChunk,
4949
startInlineScript: PrecomputedChunk,
50+
startInlineStyle: PrecomputedChunk,
5051
preamble: PreambleState,
5152
externalRuntimeScript: null | any,
5253
bootstrapChunks: Array<Chunk | PrecomputedChunk>,
@@ -99,6 +100,7 @@ export function createRenderState(
99100
segmentPrefix: renderState.segmentPrefix,
100101
boundaryPrefix: renderState.boundaryPrefix,
101102
startInlineScript: renderState.startInlineScript,
103+
startInlineStyle: renderState.startInlineStyle,
102104
preamble: renderState.preamble,
103105
externalRuntimeScript: renderState.externalRuntimeScript,
104106
bootstrapChunks: renderState.bootstrapChunks,

packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10294,6 +10294,7 @@ describe('ReactDOMFizzServer', () => {
1029410294
precedence="default"
1029510295
nonce={CSPnonce}>{`.bar { background-color: blue; }`}</style>
1029610296
</>,
10297+
{nonce: {style: CSPnonce}},
1029710298
);
1029810299
pipe(writable);
1029910300
});
@@ -10329,11 +10330,12 @@ describe('ReactDOMFizzServer', () => {
1032910330
precedence="default"
1033010331
nonce={`${CSPnonce}${CSPnonce}`}>{`.bar { background-color: blue; }`}</style>
1033110332
</>,
10333+
{nonce: {style: CSPnonce}},
1033210334
);
1033310335
pipe(writable);
1033410336
});
1033510337
assertConsoleErrorDev([
10336-
"React encountered a hoistable style tag with nonce. It doesn't match the previously encountered nonce. They have to be the same",
10338+
"React encountered a hoistable style tag with nonce. It doesn't match the previously encountered nonce. They have to be the same.",
1033710339
]);
1033810340
expect(getVisibleChildren(document)).toEqual(
1033910341
<html>

packages/react-dom/src/__tests__/ReactDOMFloat-test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8624,6 +8624,7 @@ background-color: green;
86248624
</Suspense>
86258625
</body>
86268626
</html>,
8627+
{nonce: {style: nonce}},
86278628
).pipe(writable);
86288629
});
86298630

packages/react-dom/src/server/ReactDOMFizzServerBrowser.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,12 @@ ensureCorrectIsomorphicReactVersion();
4343
type Options = {
4444
identifierPrefix?: string,
4545
namespaceURI?: string,
46-
nonce?: string,
46+
nonce?:
47+
| string
48+
| {
49+
script?: string,
50+
style?: string,
51+
},
4752
bootstrapScriptContent?: string,
4853
bootstrapScripts?: Array<string | BootstrapScriptDescriptor>,
4954
bootstrapModules?: Array<string | BootstrapScriptDescriptor>,

packages/react-dom/src/server/ReactDOMFizzServerBun.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ ensureCorrectIsomorphicReactVersion();
3737
type Options = {
3838
identifierPrefix?: string,
3939
namespaceURI?: string,
40-
nonce?: string,
40+
nonce?: string | {
41+
script?: string,
42+
style?: string,
43+
},
4144
bootstrapScriptContent?: string,
4245
bootstrapScripts?: Array<string | BootstrapScriptDescriptor>,
4346
bootstrapModules?: Array<string | BootstrapScriptDescriptor>,

0 commit comments

Comments
 (0)