Skip to content

Commit 9a0fa75

Browse files
committed
Optimizing the way external fizz runtime is instantiated so we don't have to carry the nonce around on ResponseState
1 parent 9545e48 commit 9a0fa75

3 files changed

Lines changed: 35 additions & 30 deletions

File tree

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

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,8 @@ export type ResponseState = {
130130
startInlineScript: PrecomputedChunk,
131131
instructions: InstructionState,
132132

133-
// state for outputting CSP nonce
134-
nonce: string | void,
135-
136133
// state for data streaming format
137-
externalRuntimeConfig: BootstrapScriptDescriptor | null,
134+
externalRuntimeScript: null | ExternalRuntimeScript,
138135

139136
// preamble and postamble chunks and state
140137
htmlChunks: null | Array<Chunk | PrecomputedChunk>,
@@ -196,6 +193,10 @@ export type BootstrapScriptDescriptor = {
196193
src: string,
197194
integrity?: string,
198195
};
196+
export type ExternalRuntimeScript = {
197+
src: string,
198+
chunks: Array<Chunk | PrecomputedChunk>,
199+
};
199200
// Allows us to keep track of what we've already written so we can refer back to it.
200201
// if passed externalRuntimeConfig and the enableFizzExternalRuntime feature flag
201202
// is set, the server will send instructions via data attributes (instead of inline scripts)
@@ -215,7 +216,7 @@ export function createResponseState(
215216
'<script nonce="' + escapeTextForBrowser(nonce) + '">',
216217
);
217218
const bootstrapChunks: Array<Chunk | PrecomputedChunk> = [];
218-
let externalRuntimeDesc = null;
219+
let externalRuntimeScript: null | ExternalRuntimeScript = null;
219220
let streamingFormat = ScriptStreamingFormat;
220221
if (bootstrapScriptContent !== undefined) {
221222
bootstrapChunks.push(
@@ -233,12 +234,27 @@ export function createResponseState(
233234
if (externalRuntimeConfig !== undefined) {
234235
streamingFormat = DataStreamingFormat;
235236
if (typeof externalRuntimeConfig === 'string') {
236-
externalRuntimeDesc = {
237+
externalRuntimeScript = {
237238
src: externalRuntimeConfig,
238-
integrity: undefined,
239+
chunks: [],
239240
};
241+
pushScriptImpl(externalRuntimeScript.chunks, {
242+
src: externalRuntimeConfig,
243+
async: true,
244+
integrity: undefined,
245+
nonce: nonce,
246+
});
240247
} else {
241-
externalRuntimeDesc = externalRuntimeConfig;
248+
externalRuntimeScript = {
249+
src: externalRuntimeConfig.src,
250+
chunks: [],
251+
};
252+
pushScriptImpl(externalRuntimeScript.chunks, {
253+
src: externalRuntimeConfig.src,
254+
async: true,
255+
integrity: externalRuntimeConfig.integrity,
256+
nonce: nonce,
257+
});
242258
}
243259
}
244260
}
@@ -307,7 +323,7 @@ export function createResponseState(
307323
streamingFormat,
308324
startInlineScript: inlineScriptWithNonce,
309325
instructions: NothingSent,
310-
externalRuntimeConfig: externalRuntimeDesc,
326+
externalRuntimeScript,
311327
htmlChunks: null,
312328
headChunks: null,
313329
hasBody: false,
@@ -1293,7 +1309,7 @@ function injectFormReplayingRuntime(responseState: ResponseState): void {
12931309
// to emit anything. It's always used.
12941310
if (
12951311
(responseState.instructions & SentFormReplayingRuntime) === NothingSent &&
1296-
(!enableFizzExternalRuntime || !responseState.externalRuntimeConfig)
1312+
(!enableFizzExternalRuntime || !responseState.externalRuntimeScript)
12971313
) {
12981314
responseState.instructions |= SentFormReplayingRuntime;
12991315
responseState.bootstrapChunks.unshift(
@@ -4078,15 +4094,15 @@ export function writePreamble(
40784094
if (
40794095
enableFizzExternalRuntime &&
40804096
!willFlushAllSegments &&
4081-
responseState.externalRuntimeConfig
4097+
responseState.externalRuntimeScript
40824098
) {
40834099
// If the root segment is incomplete due to suspended tasks
40844100
// (e.g. willFlushAllSegments = false) and we are using data
40854101
// streaming format, ensure the external runtime is sent.
40864102
// (User code could choose to send this even earlier by calling
40874103
// preinit(...), if they know they will suspend).
4088-
const {src, integrity} = responseState.externalRuntimeConfig;
4089-
internalPreinitScript(resources, src, integrity, responseState.nonce);
4104+
const {src, chunks} = responseState.externalRuntimeScript;
4105+
internalPreinitScript(resources, src, chunks);
40904106
}
40914107

40924108
const htmlChunks = responseState.htmlChunks;
@@ -5362,32 +5378,22 @@ function preinit(href: string, options: PreinitOptions): void {
53625378
}
53635379
}
53645380

5365-
// This method is trusted. It must only be called from within this codebase and it assumes the arguments
5366-
// conform to the types because no user input is being passed in. It also assumes that it is being called as
5367-
// part of a work or flush loop and therefore does not need to request Fizz to flush Resources.
53685381
function internalPreinitScript(
53695382
resources: Resources,
53705383
src: string,
5371-
integrity: ?string,
5372-
nonce: ?string,
5384+
chunks: Array<Chunk | PrecomputedChunk>,
53735385
): void {
53745386
const key = getResourceKey('script', src);
53755387
let resource = resources.scriptsMap.get(key);
53765388
if (!resource) {
53775389
resource = {
53785390
type: 'script',
5379-
chunks: [],
5391+
chunks,
53805392
state: NoState,
53815393
props: null,
53825394
};
53835395
resources.scriptsMap.set(key, resource);
53845396
resources.scripts.add(resource);
5385-
pushScriptImpl(resource.chunks, {
5386-
async: true,
5387-
src,
5388-
integrity,
5389-
nonce,
5390-
});
53915397
}
53925398
return;
53935399
}

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import type {
1111
BootstrapScriptDescriptor,
12+
ExternalRuntimeScript,
1213
FormatContext,
1314
StreamingFormat,
1415
InstructionState,
@@ -48,7 +49,7 @@ export type ResponseState = {
4849
streamingFormat: StreamingFormat,
4950
startInlineScript: PrecomputedChunk,
5051
instructions: InstructionState,
51-
externalRuntimeConfig: BootstrapScriptDescriptor | null,
52+
externalRuntimeScript: null | ExternalRuntimeScript,
5253
htmlChunks: null | Array<Chunk | PrecomputedChunk>,
5354
headChunks: null | Array<Chunk | PrecomputedChunk>,
5455
hasBody: boolean,
@@ -57,7 +58,6 @@ export type ResponseState = {
5758
preloadChunks: Array<Chunk | PrecomputedChunk>,
5859
hoistableChunks: Array<Chunk | PrecomputedChunk>,
5960
stylesToHoist: boolean,
60-
nonce: string | void,
6161
// This is an extra field for the legacy renderer
6262
generateStaticMarkup: boolean,
6363
};
@@ -86,7 +86,7 @@ export function createResponseState(
8686
streamingFormat: responseState.streamingFormat,
8787
startInlineScript: responseState.startInlineScript,
8888
instructions: responseState.instructions,
89-
externalRuntimeConfig: responseState.externalRuntimeConfig,
89+
externalRuntimeScript: responseState.externalRuntimeScript,
9090
htmlChunks: responseState.htmlChunks,
9191
headChunks: responseState.headChunks,
9292
hasBody: responseState.hasBody,
@@ -95,7 +95,6 @@ export function createResponseState(
9595
preloadChunks: responseState.preloadChunks,
9696
hoistableChunks: responseState.hoistableChunks,
9797
stylesToHoist: responseState.stylesToHoist,
98-
nonce: responseState.nonce,
9998

10099
// This is an extra field for the legacy renderer
101100
generateStaticMarkup,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3767,7 +3767,7 @@ describe('ReactDOMFizzServer', () => {
37673767
Array.from(document.head.getElementsByTagName('script')).map(
37683768
n => n.outerHTML,
37693769
),
3770-
).toEqual(['<script async="" src="src-of-external-runtime"></script>']);
3770+
).toEqual(['<script src="src-of-external-runtime" async=""></script>']);
37713771

37723772
expect(getVisibleChildren(document)).toEqual(
37733773
<html>

0 commit comments

Comments
 (0)