Skip to content

Commit

Permalink
Preinits should support a nonce option (facebook#26744)
Browse files Browse the repository at this point in the history
Currently there is no way to provide a nonce when using
`ReactDOM.preinit(..., { as: 'script' })`

This PR adds `nonce?: string` as an option

While implementing this PR I added a test to also show you can pass
`integrity`. This test isn't directly related to the nonce change.
  • Loading branch information
gnoff authored and AndyPengc12 committed Apr 15, 2024
1 parent b62f284 commit 4383dda
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 0 deletions.
2 changes: 2 additions & 0 deletions packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -2203,6 +2203,7 @@ type PreinitOptions = {
precedence?: string,
crossOrigin?: string,
integrity?: string,
nonce?: string,
};
function preinit(href: string, options: PreinitOptions) {
if (!enableFloat) {
Expand Down Expand Up @@ -2355,6 +2356,7 @@ function scriptPropsFromPreinitOptions(
async: true,
crossOrigin: options.crossOrigin,
integrity: options.integrity,
nonce: options.nonce,
};
}

Expand Down
2 changes: 2 additions & 0 deletions packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -5110,6 +5110,7 @@ type PreinitOptions = {
precedence?: string,
crossOrigin?: string,
integrity?: string,
nonce?: string,
};
function preinit(href: string, options: PreinitOptions): void {
if (!enableFloat) {
Expand Down Expand Up @@ -5449,6 +5450,7 @@ function scriptPropsFromPreinitOptions(
async: true,
crossOrigin: options.crossOrigin,
integrity: options.integrity,
nonce: options.nonce,
};
}

Expand Down
1 change: 1 addition & 0 deletions packages/react-dom/src/ReactDOMDispatcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export type PreinitOptions = {
precedence?: string,
crossOrigin?: string,
integrity?: string,
nonce?: string,
};

export type HostDispatcher = {
Expand Down
100 changes: 100 additions & 0 deletions packages/react-dom/src/__tests__/ReactDOMFloat-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4309,6 +4309,106 @@ body {
'ReactDOM.preinit(): For `href` "foo", the options provided conflict with another call to `ReactDOM.preinit("foo", { as: "script", ... })`. React will always use the options it first encounters when preinitializing a hoistable script for a given `href` and any later options will be ignored if different. Try updating all calls to `ReactDOM.preinit()` for a given `href` to use the same options, or only call `ReactDOM.preinit()` once per `href`.\n "integrity" option value: "some hash", missing from original options\n "crossOrigin" option value: "anonymous", original option value: "use-credentials"',
]);
});

it('accepts a `nonce` option for `as: "script"`', async () => {
function Component({src}) {
ReactDOM.preinit(src, {as: 'script', nonce: 'R4nD0m'});
return 'hello';
}

await act(() => {
renderToPipeableStream(
<html>
<body>
<Component src="foo" />
</body>
</html>,
{
nonce: 'R4nD0m',
},
).pipe(writable);
});

expect(getMeaningfulChildren(document)).toEqual(
<html>
<head>
<script async="" src="foo" nonce="R4nD0m" />
</head>
<body>hello</body>
</html>,
);

await clientAct(() => {
ReactDOMClient.hydrateRoot(
document,
<html>
<body>
<Component src="bar" />
</body>
</html>,
);
});

expect(getMeaningfulChildren(document)).toEqual(
<html>
<head>
<script async="" src="foo" nonce="R4nD0m" />
<script async="" src="bar" nonce="R4nD0m" />
</head>
<body>hello</body>
</html>,
);
});

it('accepts an `integrity` option for `as: "script"`', async () => {
function Component({src, hash}) {
ReactDOM.preinit(src, {as: 'script', integrity: hash});
return 'hello';
}

await act(() => {
renderToPipeableStream(
<html>
<body>
<Component src="foo" hash="foo hash" />
</body>
</html>,
{
nonce: 'R4nD0m',
},
).pipe(writable);
});

expect(getMeaningfulChildren(document)).toEqual(
<html>
<head>
<script async="" src="foo" integrity="foo hash" />
</head>
<body>hello</body>
</html>,
);

await clientAct(() => {
ReactDOMClient.hydrateRoot(
document,
<html>
<body>
<Component src="bar" hash="bar hash" />
</body>
</html>,
);
});

expect(getMeaningfulChildren(document)).toEqual(
<html>
<head>
<script async="" src="foo" integrity="foo hash" />
<script async="" src="bar" integrity="bar hash" />
</head>
<body>hello</body>
</html>,
);
});
});

describe('Stylesheet Resources', () => {
Expand Down

0 comments on commit 4383dda

Please sign in to comment.