mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 12:20:20 +01:00
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
This commit is contained in:
parent
5717f1933f
commit
14094f80cb
|
|
@ -135,6 +135,13 @@ const SentMarkShellTime /* */ = 0b001000000;
|
|||
const NeedUpgradeToViewTransitions /* */ = 0b010000000;
|
||||
const SentUpgradeToViewTransitions /* */ = 0b100000000;
|
||||
|
||||
type NonceOption =
|
||||
| string
|
||||
| {
|
||||
script?: string,
|
||||
style?: string,
|
||||
};
|
||||
|
||||
// Per request, global state that is not contextual to the rendering subtree.
|
||||
// This cannot be resumed and therefore should only contain things that are
|
||||
// temporary working state or are never used in the prerender pass.
|
||||
|
|
@ -147,6 +154,8 @@ export type RenderState = {
|
|||
// inline script streaming format, unused if using external runtime / data
|
||||
startInlineScript: PrecomputedChunk,
|
||||
|
||||
startInlineStyle: PrecomputedChunk,
|
||||
|
||||
// the preamble must always flush before resuming, so all these chunks must
|
||||
// be null or empty when resuming.
|
||||
|
||||
|
|
@ -209,6 +218,11 @@ export type RenderState = {
|
|||
moduleScripts: Map<string, Resource>,
|
||||
},
|
||||
|
||||
nonce: {
|
||||
script: string | void,
|
||||
style: string | void,
|
||||
},
|
||||
|
||||
// Module-global-like reference for flushing/hoisting state of style resources
|
||||
// We need to track whether the current request has flushed any style resources
|
||||
// without sending an instruction to hoist them. we do that here
|
||||
|
|
@ -295,6 +309,8 @@ export type ResumableState = {
|
|||
},
|
||||
};
|
||||
|
||||
let currentlyFlushingRenderState: RenderState | null = null;
|
||||
|
||||
const dataElementQuotedEnd = stringToPrecomputedChunk('"></template>');
|
||||
|
||||
const startInlineScript = stringToPrecomputedChunk('<script');
|
||||
|
|
@ -307,6 +323,8 @@ const scriptIntegirty = stringToPrecomputedChunk(' integrity="');
|
|||
const scriptCrossOrigin = stringToPrecomputedChunk(' crossorigin="');
|
||||
const endAsyncScript = stringToPrecomputedChunk(' async=""></script>');
|
||||
|
||||
const startInlineStyle = stringToPrecomputedChunk('<style');
|
||||
|
||||
/**
|
||||
* This escaping function is designed to work with with inline scripts where the entire
|
||||
* contents are escaped. Because we know we are escaping the entire script we can avoid for instance
|
||||
|
|
@ -365,17 +383,32 @@ if (__DEV__) {
|
|||
// is set, the server will send instructions via data attributes (instead of inline scripts)
|
||||
export function createRenderState(
|
||||
resumableState: ResumableState,
|
||||
nonce: string | void,
|
||||
nonce:
|
||||
| string
|
||||
| {
|
||||
script?: string,
|
||||
style?: string,
|
||||
}
|
||||
| void,
|
||||
externalRuntimeConfig: string | BootstrapScriptDescriptor | void,
|
||||
importMap: ImportMap | void,
|
||||
onHeaders: void | ((headers: HeadersDescriptor) => void),
|
||||
maxHeadersLength: void | number,
|
||||
): RenderState {
|
||||
const nonceScript = typeof nonce === 'string' ? nonce : nonce && nonce.script;
|
||||
const inlineScriptWithNonce =
|
||||
nonce === undefined
|
||||
nonceScript === undefined
|
||||
? startInlineScript
|
||||
: stringToPrecomputedChunk(
|
||||
'<script nonce="' + escapeTextForBrowser(nonce) + '"',
|
||||
'<script nonce="' + escapeTextForBrowser(nonceScript) + '"',
|
||||
);
|
||||
const nonceStyle =
|
||||
typeof nonce === 'string' ? undefined : nonce && nonce.style;
|
||||
const inlineStyleWithNonce =
|
||||
nonceStyle === undefined
|
||||
? startInlineStyle
|
||||
: stringToPrecomputedChunk(
|
||||
'<style nonce="' + escapeTextForBrowser(nonceStyle) + '"',
|
||||
);
|
||||
const idPrefix = resumableState.idPrefix;
|
||||
|
||||
|
|
@ -403,7 +436,7 @@ export function createRenderState(
|
|||
src: externalRuntimeConfig,
|
||||
async: true,
|
||||
integrity: undefined,
|
||||
nonce: nonce,
|
||||
nonce: nonceScript,
|
||||
});
|
||||
} else {
|
||||
externalRuntimeScript = {
|
||||
|
|
@ -414,7 +447,7 @@ export function createRenderState(
|
|||
src: externalRuntimeConfig.src,
|
||||
async: true,
|
||||
integrity: externalRuntimeConfig.integrity,
|
||||
nonce: nonce,
|
||||
nonce: nonceScript,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -459,6 +492,7 @@ export function createRenderState(
|
|||
segmentPrefix: stringToPrecomputedChunk(idPrefix + 'S:'),
|
||||
boundaryPrefix: stringToPrecomputedChunk(idPrefix + 'B:'),
|
||||
startInlineScript: inlineScriptWithNonce,
|
||||
startInlineStyle: inlineStyleWithNonce,
|
||||
preamble: createPreambleState(),
|
||||
|
||||
externalRuntimeScript: externalRuntimeScript,
|
||||
|
|
@ -500,7 +534,10 @@ export function createRenderState(
|
|||
moduleScripts: new Map(),
|
||||
},
|
||||
|
||||
nonce,
|
||||
nonce: {
|
||||
script: nonceScript,
|
||||
style: nonceStyle,
|
||||
},
|
||||
// like a module global for currently rendering boundary
|
||||
hoistableState: null,
|
||||
stylesToHoist: false,
|
||||
|
|
@ -539,10 +576,10 @@ export function createRenderState(
|
|||
stringToChunk(escapeTextForBrowser(src)),
|
||||
attributeEnd,
|
||||
);
|
||||
if (nonce) {
|
||||
if (nonceScript) {
|
||||
bootstrapChunks.push(
|
||||
scriptNonce,
|
||||
stringToChunk(escapeTextForBrowser(nonce)),
|
||||
stringToChunk(escapeTextForBrowser(nonceScript)),
|
||||
attributeEnd,
|
||||
);
|
||||
}
|
||||
|
|
@ -571,7 +608,7 @@ export function createRenderState(
|
|||
const props: PreloadModuleProps = ({
|
||||
rel: 'modulepreload',
|
||||
fetchPriority: 'low',
|
||||
nonce,
|
||||
nonce: nonceScript,
|
||||
}: any);
|
||||
if (typeof scriptConfig === 'string') {
|
||||
props.href = src = scriptConfig;
|
||||
|
|
@ -596,10 +633,10 @@ export function createRenderState(
|
|||
stringToChunk(escapeTextForBrowser(src)),
|
||||
attributeEnd,
|
||||
);
|
||||
if (nonce) {
|
||||
if (nonceScript) {
|
||||
bootstrapChunks.push(
|
||||
scriptNonce,
|
||||
stringToChunk(escapeTextForBrowser(nonce)),
|
||||
stringToChunk(escapeTextForBrowser(nonceScript)),
|
||||
attributeEnd,
|
||||
);
|
||||
}
|
||||
|
|
@ -627,7 +664,7 @@ export function createRenderState(
|
|||
|
||||
export function resumeRenderState(
|
||||
resumableState: ResumableState,
|
||||
nonce: string | void,
|
||||
nonce: NonceOption | void,
|
||||
): RenderState {
|
||||
return createRenderState(
|
||||
resumableState,
|
||||
|
|
@ -3046,6 +3083,7 @@ function pushStyle(
|
|||
}
|
||||
const precedence = props.precedence;
|
||||
const href = props.href;
|
||||
const nonce = props.nonce;
|
||||
|
||||
if (
|
||||
formatContext.insertionMode === SVG_MODE ||
|
||||
|
|
@ -3091,15 +3129,33 @@ function pushStyle(
|
|||
styleQueue = {
|
||||
precedence: stringToChunk(escapeTextForBrowser(precedence)),
|
||||
rules: ([]: Array<Chunk | PrecomputedChunk>),
|
||||
hrefs: [stringToChunk(escapeTextForBrowser(href))],
|
||||
hrefs: ([]: Array<Chunk | PrecomputedChunk>),
|
||||
sheets: (new Map(): Map<string, StylesheetResource>),
|
||||
};
|
||||
renderState.styles.set(precedence, styleQueue);
|
||||
} else {
|
||||
// We have seen this precedence before and need to track this href
|
||||
styleQueue.hrefs.push(stringToChunk(escapeTextForBrowser(href)));
|
||||
}
|
||||
|
||||
const nonceStyle = renderState.nonce.style;
|
||||
if (!nonceStyle || nonceStyle === nonce) {
|
||||
if (__DEV__) {
|
||||
if (!nonceStyle && nonce) {
|
||||
console.error(
|
||||
'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.',
|
||||
precedence,
|
||||
nonce,
|
||||
);
|
||||
}
|
||||
}
|
||||
styleQueue.hrefs.push(stringToChunk(escapeTextForBrowser(href)));
|
||||
pushStyleContents(styleQueue.rules, props);
|
||||
} else if (__DEV__) {
|
||||
console.error(
|
||||
'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.',
|
||||
precedence,
|
||||
nonce,
|
||||
nonceStyle,
|
||||
);
|
||||
}
|
||||
}
|
||||
if (styleQueue) {
|
||||
// We need to track whether this boundary should wait on this resource or not.
|
||||
|
|
@ -5148,7 +5204,7 @@ function escapeJSObjectForInstructionScripts(input: Object): string {
|
|||
}
|
||||
|
||||
const lateStyleTagResourceOpen1 = stringToPrecomputedChunk(
|
||||
'<style media="not all" data-precedence="',
|
||||
' media="not all" data-precedence="',
|
||||
);
|
||||
const lateStyleTagResourceOpen2 = stringToPrecomputedChunk('" data-href="');
|
||||
const lateStyleTagResourceOpen3 = stringToPrecomputedChunk('">');
|
||||
|
|
@ -5176,6 +5232,10 @@ function flushStyleTagsLateForBoundary(
|
|||
}
|
||||
let i = 0;
|
||||
if (hrefs.length) {
|
||||
writeChunk(
|
||||
this,
|
||||
((currentlyFlushingRenderState: any): RenderState).startInlineStyle,
|
||||
);
|
||||
writeChunk(this, lateStyleTagResourceOpen1);
|
||||
writeChunk(this, styleQueue.precedence);
|
||||
writeChunk(this, lateStyleTagResourceOpen2);
|
||||
|
|
@ -5225,7 +5285,9 @@ export function writeHoistablesForBoundary(
|
|||
destinationHasCapacity = true;
|
||||
|
||||
// Flush style tags for each precedence this boundary depends on
|
||||
currentlyFlushingRenderState = renderState;
|
||||
hoistableState.styles.forEach(flushStyleTagsLateForBoundary, destination);
|
||||
currentlyFlushingRenderState = null;
|
||||
|
||||
// Determine if this boundary has stylesheets that need to be awaited upon completion
|
||||
hoistableState.stylesheets.forEach(hasStylesToHoist);
|
||||
|
|
@ -5268,9 +5330,7 @@ function flushStyleInPreamble(
|
|||
stylesheet.state = PREAMBLE;
|
||||
}
|
||||
|
||||
const styleTagResourceOpen1 = stringToPrecomputedChunk(
|
||||
'<style data-precedence="',
|
||||
);
|
||||
const styleTagResourceOpen1 = stringToPrecomputedChunk(' data-precedence="');
|
||||
const styleTagResourceOpen2 = stringToPrecomputedChunk('" data-href="');
|
||||
const spaceSeparator = stringToPrecomputedChunk(' ');
|
||||
const styleTagResourceOpen3 = stringToPrecomputedChunk('">');
|
||||
|
|
@ -5292,6 +5352,10 @@ function flushStylesInPreamble(
|
|||
// order so even if there are no rules for style tags at this precedence we emit an empty style
|
||||
// tag with the data-precedence attribute
|
||||
if (!hasStylesheets || hrefs.length) {
|
||||
writeChunk(
|
||||
this,
|
||||
((currentlyFlushingRenderState: any): RenderState).startInlineStyle,
|
||||
);
|
||||
writeChunk(this, styleTagResourceOpen1);
|
||||
writeChunk(this, styleQueue.precedence);
|
||||
let i = 0;
|
||||
|
|
@ -5466,7 +5530,9 @@ export function writePreambleStart(
|
|||
renderState.highImagePreloads.clear();
|
||||
|
||||
// Flush unblocked stylesheets by precedence
|
||||
currentlyFlushingRenderState = renderState;
|
||||
renderState.styles.forEach(flushStylesInPreamble, destination);
|
||||
currentlyFlushingRenderState = null;
|
||||
|
||||
const importMapChunks = renderState.importMapChunks;
|
||||
for (i = 0; i < importMapChunks.length; i++) {
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ export type RenderState = {
|
|||
segmentPrefix: PrecomputedChunk,
|
||||
boundaryPrefix: PrecomputedChunk,
|
||||
startInlineScript: PrecomputedChunk,
|
||||
startInlineStyle: PrecomputedChunk,
|
||||
preamble: PreambleState,
|
||||
externalRuntimeScript: null | any,
|
||||
bootstrapChunks: Array<Chunk | PrecomputedChunk>,
|
||||
|
|
@ -76,6 +77,10 @@ export type RenderState = {
|
|||
scripts: Map<string, Resource>,
|
||||
moduleScripts: Map<string, Resource>,
|
||||
},
|
||||
nonce: {
|
||||
script: string | void,
|
||||
style: string | void,
|
||||
},
|
||||
stylesToHoist: boolean,
|
||||
// This is an extra field for the legacy renderer
|
||||
generateStaticMarkup: boolean,
|
||||
|
|
@ -99,6 +104,7 @@ export function createRenderState(
|
|||
segmentPrefix: renderState.segmentPrefix,
|
||||
boundaryPrefix: renderState.boundaryPrefix,
|
||||
startInlineScript: renderState.startInlineScript,
|
||||
startInlineStyle: renderState.startInlineStyle,
|
||||
preamble: renderState.preamble,
|
||||
externalRuntimeScript: renderState.externalRuntimeScript,
|
||||
bootstrapChunks: renderState.bootstrapChunks,
|
||||
|
|
@ -118,6 +124,7 @@ export function createRenderState(
|
|||
scripts: renderState.scripts,
|
||||
bulkPreloads: renderState.bulkPreloads,
|
||||
preloads: renderState.preloads,
|
||||
nonce: renderState.nonce,
|
||||
stylesToHoist: renderState.stylesToHoist,
|
||||
|
||||
// This is an extra field for the legacy renderer
|
||||
|
|
|
|||
|
|
@ -10279,4 +10279,172 @@ describe('ReactDOMFizzServer', () => {
|
|||
</html>,
|
||||
);
|
||||
});
|
||||
|
||||
it('can render styles with nonce', async () => {
|
||||
CSPnonce = 'R4nd0m';
|
||||
await act(() => {
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<>
|
||||
<style
|
||||
href="foo"
|
||||
precedence="default"
|
||||
nonce={CSPnonce}>{`.foo { color: hotpink; }`}</style>
|
||||
<style
|
||||
href="bar"
|
||||
precedence="default"
|
||||
nonce={CSPnonce}>{`.bar { background-color: blue; }`}</style>
|
||||
</>,
|
||||
{nonce: {style: CSPnonce}},
|
||||
);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(document.querySelector('style').nonce).toBe(CSPnonce);
|
||||
expect(getVisibleChildren(document)).toEqual(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
<div id="container">
|
||||
<style
|
||||
data-precedence="default"
|
||||
data-href="foo bar"
|
||||
nonce={
|
||||
CSPnonce
|
||||
}>{`.foo { color: hotpink; }.bar { background-color: blue; }`}</style>
|
||||
</div>
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
});
|
||||
|
||||
it("shouldn't render styles with mismatched nonce", async () => {
|
||||
CSPnonce = 'R4nd0m';
|
||||
await act(() => {
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<>
|
||||
<style
|
||||
href="foo"
|
||||
precedence="default"
|
||||
nonce={CSPnonce}>{`.foo { color: hotpink; }`}</style>
|
||||
<style
|
||||
href="bar"
|
||||
precedence="default"
|
||||
nonce={`${CSPnonce}${CSPnonce}`}>{`.bar { background-color: blue; }`}</style>
|
||||
</>,
|
||||
{nonce: {style: CSPnonce}},
|
||||
);
|
||||
pipe(writable);
|
||||
});
|
||||
assertConsoleErrorDev([
|
||||
'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.',
|
||||
]);
|
||||
expect(getVisibleChildren(document)).toEqual(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
<div id="container">
|
||||
<style
|
||||
data-precedence="default"
|
||||
data-href="foo"
|
||||
nonce={CSPnonce}>{`.foo { color: hotpink; }`}</style>
|
||||
</div>
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
});
|
||||
|
||||
it("should render styles without nonce when render call doesn't receive nonce", async () => {
|
||||
await act(() => {
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<>
|
||||
<style
|
||||
href="foo"
|
||||
precedence="default"
|
||||
nonce="R4nd0m">{`.foo { color: hotpink; }`}</style>
|
||||
</>,
|
||||
);
|
||||
pipe(writable);
|
||||
});
|
||||
assertConsoleErrorDev([
|
||||
'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.',
|
||||
]);
|
||||
expect(getVisibleChildren(document)).toEqual(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
<div id="container">
|
||||
<style
|
||||
data-precedence="default"
|
||||
data-href="foo">{`.foo { color: hotpink; }`}</style>
|
||||
</div>
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
});
|
||||
|
||||
it('should render styles without nonce when render call receives a string nonce dedicated to scripts', async () => {
|
||||
CSPnonce = 'R4nd0m';
|
||||
await act(() => {
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<>
|
||||
<style
|
||||
href="foo"
|
||||
precedence="default"
|
||||
nonce={CSPnonce}>{`.foo { color: hotpink; }`}</style>
|
||||
</>,
|
||||
{nonce: CSPnonce},
|
||||
);
|
||||
pipe(writable);
|
||||
});
|
||||
assertConsoleErrorDev([
|
||||
'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.',
|
||||
]);
|
||||
expect(getVisibleChildren(document)).toEqual(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
<div id="container">
|
||||
<style
|
||||
data-precedence="default"
|
||||
data-href="foo">{`.foo { color: hotpink; }`}</style>
|
||||
</div>
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
});
|
||||
|
||||
it('should allow for different script and style nonces', async () => {
|
||||
CSPnonce = 'R4nd0m';
|
||||
await act(() => {
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<>
|
||||
<style
|
||||
href="foo"
|
||||
precedence="default"
|
||||
nonce="D1ff3r3nt">{`.foo { color: hotpink; }`}</style>
|
||||
</>,
|
||||
{
|
||||
nonce: {script: CSPnonce, style: 'D1ff3r3nt'},
|
||||
bootstrapScriptContent: 'function noop(){}',
|
||||
},
|
||||
);
|
||||
pipe(writable);
|
||||
});
|
||||
const scripts = Array.from(container.getElementsByTagName('script')).filter(
|
||||
node => node.getAttribute('nonce') === CSPnonce,
|
||||
);
|
||||
expect(scripts[scripts.length - 1].textContent).toBe('function noop(){}');
|
||||
expect(getVisibleChildren(document)).toEqual(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
<div id="container">
|
||||
<style
|
||||
data-precedence="default"
|
||||
data-href="foo"
|
||||
nonce="D1ff3r3nt">{`.foo { color: hotpink; }`}</style>
|
||||
</div>
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -8595,6 +8595,86 @@ background-color: green;
|
|||
' in style (at **)',
|
||||
]);
|
||||
});
|
||||
|
||||
it('can emit styles with nonce', async () => {
|
||||
const nonce = 'R4nD0m';
|
||||
const fooCss = '.foo { color: hotpink; }';
|
||||
const barCss = '.bar { background-color: blue; }';
|
||||
const bazCss = '.baz { border: 1px solid black; }';
|
||||
await act(() => {
|
||||
renderToPipeableStream(
|
||||
<html>
|
||||
<body>
|
||||
<Suspense>
|
||||
<BlockedOn value="first">
|
||||
<div>first</div>
|
||||
<style href="foo" precedence="default" nonce={nonce}>
|
||||
{fooCss}
|
||||
</style>
|
||||
<style href="bar" precedence="default" nonce={nonce}>
|
||||
{barCss}
|
||||
</style>
|
||||
<BlockedOn value="second">
|
||||
<div>second</div>
|
||||
<style href="baz" precedence="default" nonce={nonce}>
|
||||
{bazCss}
|
||||
</style>
|
||||
</BlockedOn>
|
||||
</BlockedOn>
|
||||
</Suspense>
|
||||
</body>
|
||||
</html>,
|
||||
{nonce: {style: nonce}},
|
||||
).pipe(writable);
|
||||
});
|
||||
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head />
|
||||
<body />
|
||||
</html>,
|
||||
);
|
||||
|
||||
await act(() => {
|
||||
resolveText('first');
|
||||
});
|
||||
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
<style
|
||||
data-href="foo bar"
|
||||
data-precedence="default"
|
||||
media="not all"
|
||||
nonce={nonce}>
|
||||
{`${fooCss}${barCss}`}
|
||||
</style>
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
|
||||
await act(() => {
|
||||
resolveText('second');
|
||||
});
|
||||
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
<style data-href="foo bar" data-precedence="default" nonce={nonce}>
|
||||
{`${fooCss}${barCss}`}
|
||||
</style>
|
||||
<style data-href="baz" data-precedence="default" nonce={nonce}>
|
||||
{bazCss}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div>first</div>
|
||||
<div>second</div>
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Script Resources', () => {
|
||||
|
|
|
|||
|
|
@ -40,10 +40,17 @@ import {
|
|||
import {ensureCorrectIsomorphicReactVersion} from '../shared/ensureCorrectIsomorphicReactVersion';
|
||||
ensureCorrectIsomorphicReactVersion();
|
||||
|
||||
type NonceOption =
|
||||
| string
|
||||
| {
|
||||
script?: string,
|
||||
style?: string,
|
||||
};
|
||||
|
||||
type Options = {
|
||||
identifierPrefix?: string,
|
||||
namespaceURI?: string,
|
||||
nonce?: string,
|
||||
nonce?: NonceOption,
|
||||
bootstrapScriptContent?: string,
|
||||
bootstrapScripts?: Array<string | BootstrapScriptDescriptor>,
|
||||
bootstrapModules?: Array<string | BootstrapScriptDescriptor>,
|
||||
|
|
@ -59,7 +66,7 @@ type Options = {
|
|||
};
|
||||
|
||||
type ResumeOptions = {
|
||||
nonce?: string,
|
||||
nonce?: NonceOption,
|
||||
signal?: AbortSignal,
|
||||
onError?: (error: mixed) => ?string,
|
||||
onPostpone?: (reason: string) => void,
|
||||
|
|
|
|||
|
|
@ -37,7 +37,12 @@ ensureCorrectIsomorphicReactVersion();
|
|||
type Options = {
|
||||
identifierPrefix?: string,
|
||||
namespaceURI?: string,
|
||||
nonce?: string,
|
||||
nonce?:
|
||||
| string
|
||||
| {
|
||||
script?: string,
|
||||
style?: string,
|
||||
},
|
||||
bootstrapScriptContent?: string,
|
||||
bootstrapScripts?: Array<string | BootstrapScriptDescriptor>,
|
||||
bootstrapModules?: Array<string | BootstrapScriptDescriptor>,
|
||||
|
|
|
|||
|
|
@ -40,10 +40,17 @@ import {
|
|||
import {ensureCorrectIsomorphicReactVersion} from '../shared/ensureCorrectIsomorphicReactVersion';
|
||||
ensureCorrectIsomorphicReactVersion();
|
||||
|
||||
type NonceOption =
|
||||
| string
|
||||
| {
|
||||
script?: string,
|
||||
style?: string,
|
||||
};
|
||||
|
||||
type Options = {
|
||||
identifierPrefix?: string,
|
||||
namespaceURI?: string,
|
||||
nonce?: string,
|
||||
nonce?: NonceOption,
|
||||
bootstrapScriptContent?: string,
|
||||
bootstrapScripts?: Array<string | BootstrapScriptDescriptor>,
|
||||
bootstrapModules?: Array<string | BootstrapScriptDescriptor>,
|
||||
|
|
@ -59,7 +66,7 @@ type Options = {
|
|||
};
|
||||
|
||||
type ResumeOptions = {
|
||||
nonce?: string,
|
||||
nonce?: NonceOption,
|
||||
signal?: AbortSignal,
|
||||
onError?: (error: mixed) => ?string,
|
||||
onPostpone?: (reason: string) => void,
|
||||
|
|
|
|||
|
|
@ -56,10 +56,17 @@ function createCancelHandler(request: Request, reason: string) {
|
|||
};
|
||||
}
|
||||
|
||||
type NonceOption =
|
||||
| string
|
||||
| {
|
||||
script?: string,
|
||||
style?: string,
|
||||
};
|
||||
|
||||
type Options = {
|
||||
identifierPrefix?: string,
|
||||
namespaceURI?: string,
|
||||
nonce?: string,
|
||||
nonce?: NonceOption,
|
||||
bootstrapScriptContent?: string,
|
||||
bootstrapScripts?: Array<string | BootstrapScriptDescriptor>,
|
||||
bootstrapModules?: Array<string | BootstrapScriptDescriptor>,
|
||||
|
|
@ -77,7 +84,7 @@ type Options = {
|
|||
};
|
||||
|
||||
type ResumeOptions = {
|
||||
nonce?: string,
|
||||
nonce?: NonceOption,
|
||||
onShellReady?: () => void,
|
||||
onShellError?: (error: mixed) => void,
|
||||
onAllReady?: () => void,
|
||||
|
|
|
|||
|
|
@ -43,6 +43,13 @@ import {enablePostpone, enableHalt} from 'shared/ReactFeatureFlags';
|
|||
import {ensureCorrectIsomorphicReactVersion} from '../shared/ensureCorrectIsomorphicReactVersion';
|
||||
ensureCorrectIsomorphicReactVersion();
|
||||
|
||||
type NonceOption =
|
||||
| string
|
||||
| {
|
||||
script?: string,
|
||||
style?: string,
|
||||
};
|
||||
|
||||
type Options = {
|
||||
identifierPrefix?: string,
|
||||
namespaceURI?: string,
|
||||
|
|
@ -151,7 +158,7 @@ function prerender(
|
|||
}
|
||||
|
||||
type ResumeOptions = {
|
||||
nonce?: string,
|
||||
nonce?: NonceOption,
|
||||
signal?: AbortSignal,
|
||||
onError?: (error: mixed) => ?string,
|
||||
onPostpone?: (reason: string) => void,
|
||||
|
|
|
|||
|
|
@ -43,6 +43,13 @@ import {enablePostpone, enableHalt} from 'shared/ReactFeatureFlags';
|
|||
import {ensureCorrectIsomorphicReactVersion} from '../shared/ensureCorrectIsomorphicReactVersion';
|
||||
ensureCorrectIsomorphicReactVersion();
|
||||
|
||||
type NonceOption =
|
||||
| string
|
||||
| {
|
||||
script?: string,
|
||||
style?: string,
|
||||
};
|
||||
|
||||
type Options = {
|
||||
identifierPrefix?: string,
|
||||
namespaceURI?: string,
|
||||
|
|
@ -150,7 +157,7 @@ function prerender(
|
|||
}
|
||||
|
||||
type ResumeOptions = {
|
||||
nonce?: string,
|
||||
nonce?: NonceOption,
|
||||
signal?: AbortSignal,
|
||||
onError?: (error: mixed) => ?string,
|
||||
onPostpone?: (reason: string) => void,
|
||||
|
|
|
|||
|
|
@ -44,6 +44,13 @@ import {enablePostpone, enableHalt} from 'shared/ReactFeatureFlags';
|
|||
import {ensureCorrectIsomorphicReactVersion} from '../shared/ensureCorrectIsomorphicReactVersion';
|
||||
ensureCorrectIsomorphicReactVersion();
|
||||
|
||||
type NonceOption =
|
||||
| string
|
||||
| {
|
||||
script?: string,
|
||||
style?: string,
|
||||
};
|
||||
|
||||
type Options = {
|
||||
identifierPrefix?: string,
|
||||
namespaceURI?: string,
|
||||
|
|
@ -151,7 +158,7 @@ function prerenderToNodeStream(
|
|||
}
|
||||
|
||||
type ResumeOptions = {
|
||||
nonce?: string,
|
||||
nonce?: NonceOption,
|
||||
signal?: AbortSignal,
|
||||
onError?: (error: mixed, errorInfo: ErrorInfo) => ?string,
|
||||
onPostpone?: (reason: string, postponeInfo: PostponeInfo) => void,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user