[Float] Forward `nonce` option in `ReactDOM.preloadModule()` (#36851)
udit committed
Jun 29, 2026 at 07:33 UTC
6befd1ae6299a44c49aa704564b3de09496432f8
5 files changed
+37
-5
.eslintrc.js
+1
@@ -622,6 +622,7 @@ module.exports = {
622
ReadableStreamReader: 'readonly',
623
RequestInfo: 'readonly',
624
RequestOptions: 'readonly',
625
+ Required: 'readonly',
626
StoreAsGlobal: 'readonly',
627
symbol: 'readonly',
628
SyntheticEvent: 'readonly',
packages/react-dom-bindings/src/shared/ReactFlightClientConfigDOM.js
+4
@@ -118,7 +118,9 @@ export function preinitModuleForSSR(
118
ReactDOMSharedInternals.d /* ReactDOMCurrentDispatcher */
119
.M(/* preinitModuleScript */ href, {
120
crossOrigin: getCrossOriginString(crossOrigin),
121
+ integrity: undefined,
122
nonce,
123
+ fetchPriority: undefined,
124
});
125
}
126
@@ -130,6 +132,8 @@ export function preinitScriptForSSR(
132
ReactDOMSharedInternals.d /* ReactDOMCurrentDispatcher */
133
.X(/* preinitScript */ href, {
134
crossOrigin: getCrossOriginString(crossOrigin),
135
+ integrity: undefined,
136
+ fetchPriority: undefined,
137
nonce,
138
});
139
}
packages/react-dom/src/__tests__/ReactDOMFloat-test.js
+23
@@ -6621,6 +6621,29 @@ body {
6621
);
6622
});
6623
6624
+ it('supports nonce', async () => {
6625
+ function App({ssr}) {
6626
+ const prefix = ssr ? 'ssr ' : 'browser ';
6627
+ ReactDOM.preloadModule(prefix + 'module', {nonce: 'abc'});
6628
+ return <div>hello</div>;
6629
+ }
6630
+ await act(() => {
6631
+ renderToPipeableStream(<App ssr={true} />).pipe(writable);
6632
+ });
6633
+ expect(getMeaningfulChildren(document.body)).toEqual(
6634
+ <div id="container">
6635
+ <link rel="modulepreload" href="ssr module" nonce="abc" />
6636
+ <div>hello</div>
6637
+ </div>,
6638
+ );
6639
+
6640
+ ReactDOMClient.hydrateRoot(container, <App />);
6641
+ await waitForAll([]);
6642
+ expect(getMeaningfulChildren(document.head)).toEqual(
6643
+ <link rel="modulepreload" href="browser module" nonce="abc" />,
6644
+ );
6645
+ });
6646
+
6647
it('warns if you provide invalid arguments', async () => {
6648
function App() {
6649
ReactDOM.preloadModule();
packages/react-dom/src/shared/ReactDOMFloat.js
+1
@@ -192,6 +192,7 @@ export function preloadModule(href: string, options?: ?PreloadModuleOptions) {
192
typeof options.integrity === 'string'
193
? options.integrity
194
: undefined,
195
+ nonce: typeof options.nonce === 'string' ? options.nonce : undefined,
196
fetchPriority:
197
typeof options.fetchPriority === 'string'
198
? options.fetchPriority
packages/react-dom/src/shared/ReactDOMTypes.js
+8
-5
@@ -93,21 +93,24 @@ export type HostDispatcher = {
93
L /* preload */: (
94
href: string,
95
as: string,
96
- options?: ?PreloadImplOptions,
96
+ options?: ?Required<PreloadImplOptions>,
97
) => void,
98
m /* preloadModule */: (
99
href: string,
100
- options?: ?PreloadModuleImplOptions,
100
+ options?: ?Required<PreloadModuleImplOptions>,
101
) => void,
102
S /* preinitStyle */: (
103
href: string,
104
precedence: ?string,
105
- options?: ?PreinitStyleOptions,
105
+ options?: ?Required<PreinitStyleOptions>,
106
+ ) => void,
107
+ X /* preinitScript */: (
108
+ src: string,
109
+ options?: ?Required<PreinitScriptOptions>,
110
) => void,
107
- X /* preinitScript */: (src: string, options?: ?PreinitScriptOptions) => void,
111
M /* preinitModuleScript */: (
112
src: string,
110
- options?: ?PreinitModuleScriptOptions,
113
+ options?: ?Required<PreinitModuleScriptOptions>,
114
) => void,
115
};
116