From e5c2ed4c2690410d97dd6cdbb69f5513b81235de Mon Sep 17 00:00:00 2001 From: Josh Story Date: Wed, 31 May 2023 11:15:41 -0700 Subject: [PATCH] support fetchPriority as an option for ReactDOM.preload() and ReactDOM.preinit() --- .../src/client/ReactFiberConfigDOM.js | 5 + .../src/server/ReactFizzConfigDOM.js | 5 + packages/react-dom/src/ReactDOMDispatcher.js | 2 + .../src/__tests__/ReactDOMFloat-test.js | 200 +++++++++++++++++- 4 files changed, 210 insertions(+), 2 deletions(-) diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js index b5bac943daf1f..d75afafcff8e1 100644 --- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js +++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js @@ -2161,6 +2161,7 @@ type PreloadOptions = { crossOrigin?: string, integrity?: string, type?: string, + fetchPriority?: 'high' | 'low' | 'auto', }; function preload(href: string, options: PreloadOptions) { if (!enableFloat) { @@ -2233,6 +2234,7 @@ function preloadPropsFromPreloadOptions( crossOrigin: as === 'font' ? '' : options.crossOrigin, integrity: options.integrity, type: options.type, + fetchPriority: options.fetchPriority, }; } @@ -2242,6 +2244,7 @@ type PreinitOptions = { crossOrigin?: string, integrity?: string, nonce?: string, + fetchPriority?: 'high' | 'low' | 'auto', }; function preinit(href: string, options: PreinitOptions) { if (!enableFloat) { @@ -2383,6 +2386,7 @@ function stylesheetPropsFromPreinitOptions( 'data-precedence': precedence, crossOrigin: options.crossOrigin, integrity: options.integrity, + fetchPriority: options.fetchPriority, }; } @@ -2396,6 +2400,7 @@ function scriptPropsFromPreinitOptions( crossOrigin: options.crossOrigin, integrity: options.integrity, nonce: options.nonce, + fetchPriority: options.fetchPriority, }; } diff --git a/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js b/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js index e67fb032e642f..0185fe4a6a5ab 100644 --- a/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js +++ b/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js @@ -5010,6 +5010,7 @@ type PreloadOptions = { crossOrigin?: string, integrity?: string, type?: string, + fetchPriority?: 'high' | 'low' | 'auto', }; export function preload(href: string, options: PreloadOptions) { if (!enableFloat) { @@ -5155,6 +5156,7 @@ type PreinitOptions = { crossOrigin?: string, integrity?: string, nonce?: string, + fetchPriority?: 'high' | 'low' | 'auto', }; function preinit(href: string, options: PreinitOptions): void { if (!enableFloat) { @@ -5418,6 +5420,7 @@ function preloadPropsFromPreloadOptions( crossOrigin: as === 'font' ? '' : options.crossOrigin, integrity: options.integrity, type: options.type, + fetchPriority: options.fetchPriority, }; } @@ -5446,6 +5449,7 @@ function stylesheetPropsFromPreinitOptions( 'data-precedence': precedence, crossOrigin: options.crossOrigin, integrity: options.integrity, + fetchPriority: options.fetchPriority, }; } @@ -5477,6 +5481,7 @@ function scriptPropsFromPreinitOptions( crossOrigin: options.crossOrigin, integrity: options.integrity, nonce: options.nonce, + fetchPriority: options.fetchPriority, }; } diff --git a/packages/react-dom/src/ReactDOMDispatcher.js b/packages/react-dom/src/ReactDOMDispatcher.js index 0c2b85945006b..2bd42537400a0 100644 --- a/packages/react-dom/src/ReactDOMDispatcher.js +++ b/packages/react-dom/src/ReactDOMDispatcher.js @@ -14,6 +14,7 @@ export type PreloadOptions = { crossOrigin?: string, integrity?: string, type?: string, + fetchPriority?: 'high' | 'low' | 'auto', }; export type PreinitOptions = { as: string, @@ -21,6 +22,7 @@ export type PreinitOptions = { crossOrigin?: string, integrity?: string, nonce?: string, + fetchPriority?: 'high' | 'low' | 'auto', }; export type HostDispatcher = { diff --git a/packages/react-dom/src/__tests__/ReactDOMFloat-test.js b/packages/react-dom/src/__tests__/ReactDOMFloat-test.js index 6c087388cc681..07c13b764a37e 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFloat-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFloat-test.js @@ -3873,6 +3873,113 @@ body { 'Warning: ReactDOM.preload(): The options provided conflict with another call to `ReactDOM.preload("foo", { as: "font", ...})`. React will always use the options it first encounters when preloading a resource for a given `href` and `as` type, and any later options will be ignored if different. Try updating all calls to `ReactDOM.preload()` with the same `href` and `as` type to use the same options, or eliminate one of the calls.\n "crossOrigin" missing from options, original option value: "use-credentials"', ]); }); + + it('supports fetchPriority', async () => { + function Component({isServer}) { + ReactDOM.preload(isServer ? 'highserver' : 'highclient', { + as: 'script', + fetchPriority: 'high', + }); + ReactDOM.preload(isServer ? 'lowserver' : 'lowclient', { + as: 'style', + fetchPriority: 'low', + }); + ReactDOM.preload(isServer ? 'autoserver' : 'autoclient', { + as: 'style', + fetchPriority: 'auto', + }); + return 'hello'; + } + + await act(() => { + renderToPipeableStream( + + + + + , + ).pipe(writable); + }); + + expect(getMeaningfulChildren(document)).toEqual( + + + + + + + hello + , + ); + + ReactDOMClient.hydrateRoot( + document, + + + + + , + ); + await waitForAll([]); + expect(getMeaningfulChildren(document)).toEqual( + + + + + + + + + + hello + , + ); + }); }); describe('ReactDOM.preinit(href, { as: ... })', () => { @@ -4406,7 +4513,6 @@ body { hello , ); - await clientAct(() => { ReactDOMClient.hydrateRoot( document, @@ -4417,7 +4523,6 @@ body { , ); }); - expect(getMeaningfulChildren(document)).toEqual( @@ -4438,6 +4543,97 @@ body { , ); }); + + it('supports fetchPriority', async () => { + function Component({isServer}) { + ReactDOM.preinit(isServer ? 'highserver' : 'highclient', { + as: 'script', + fetchPriority: 'high', + }); + ReactDOM.preinit(isServer ? 'lowserver' : 'lowclient', { + as: 'style', + fetchPriority: 'low', + }); + ReactDOM.preinit(isServer ? 'autoserver' : 'autoclient', { + as: 'style', + fetchPriority: 'auto', + }); + return 'hello'; + } + + await act(() => { + renderToPipeableStream( + + + + + , + ).pipe(writable); + }); + + expect(getMeaningfulChildren(document)).toEqual( + + + + +