@samitouri / QOS-React-2 / commits / 042d8f606c

[Float] support fetchpriority on `ReactDOM.preload()` and `ReactDOM.preinit()` (#26880)

exposes fetchPriority as an option for `ReactDOM.preload()` and `ReactDOM.preinit()` the typings should be `'high' | 'low' | 'auto'`

Josh Story committed Jun 1, 2023 at 13:10 UTC 042d8f606ce643d2eca955badbf07ea5b8ac266c
4 files changed +211 -2
packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js
+5
@@ -2173,6 +2173,7 @@ type PreloadOptions = {
2173 crossOrigin?: string,
2174 integrity?: string,
2175 type?: string,
2176 + fetchPriority?: 'high' | 'low' | 'auto',
2177 };
2178 function preload(href: string, options: PreloadOptions) {
2179 if (!enableFloat) {
@@ -2245,6 +2246,7 @@ function preloadPropsFromPreloadOptions(
2246 crossOrigin: as === 'font' ? '' : options.crossOrigin,
2247 integrity: options.integrity,
2248 type: options.type,
2249 + fetchPriority: options.fetchPriority,
2250 };
2251 }
2252
@@ -2254,6 +2256,7 @@ type PreinitOptions = {
2256 crossOrigin?: string,
2257 integrity?: string,
2258 nonce?: string,
2259 + fetchPriority?: 'high' | 'low' | 'auto',
2260 };
2261 function preinit(href: string, options: PreinitOptions) {
2262 if (!enableFloat) {
@@ -2395,6 +2398,7 @@ function stylesheetPropsFromPreinitOptions(
2398 'data-precedence': precedence,
2399 crossOrigin: options.crossOrigin,
2400 integrity: options.integrity,
2401 + fetchPriority: options.fetchPriority,
2402 };
2403 }
2404
@@ -2408,6 +2412,7 @@ function scriptPropsFromPreinitOptions(
2412 crossOrigin: options.crossOrigin,
2413 integrity: options.integrity,
2414 nonce: options.nonce,
2415 + fetchPriority: options.fetchPriority,
2416 };
2417 }
2418
packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js
+5
@@ -5102,6 +5102,7 @@ type PreloadOptions = {
5102 crossOrigin?: string,
5103 integrity?: string,
5104 type?: string,
5105 + fetchPriority?: 'high' | 'low' | 'auto',
5106 };
5107 export function preload(href: string, options: PreloadOptions) {
5108 if (!enableFloat) {
@@ -5247,6 +5248,7 @@ type PreinitOptions = {
5248 crossOrigin?: string,
5249 integrity?: string,
5250 nonce?: string,
5251 + fetchPriority?: 'high' | 'low' | 'auto',
5252 };
5253 function preinit(href: string, options: PreinitOptions): void {
5254 if (!enableFloat) {
@@ -5590,6 +5592,7 @@ function preloadPropsFromPreloadOptions(
5592 crossOrigin: as === 'font' ? '' : options.crossOrigin,
5593 integrity: options.integrity,
5594 type: options.type,
5595 + fetchPriority: options.fetchPriority,
5596 };
5597 }
5598
@@ -5631,6 +5634,7 @@ function stylesheetPropsFromPreinitOptions(
5634 'data-precedence': precedence,
5635 crossOrigin: options.crossOrigin,
5636 integrity: options.integrity,
5637 + fetchPriority: options.fetchPriority,
5638 };
5639 }
5640
@@ -5662,6 +5666,7 @@ function scriptPropsFromPreinitOptions(
5666 crossOrigin: options.crossOrigin,
5667 integrity: options.integrity,
5668 nonce: options.nonce,
5669 + fetchPriority: options.fetchPriority,
5670 };
5671 }
5672
packages/react-dom/src/ReactDOMDispatcher.js
+2
@@ -14,6 +14,7 @@ export type PreloadOptions = {
14 crossOrigin?: string,
15 integrity?: string,
16 type?: string,
17 + fetchPriority?: 'high' | 'low' | 'auto',
18 };
19 export type PreinitOptions = {
20 as: string,
@@ -21,6 +22,7 @@ export type PreinitOptions = {
22 crossOrigin?: string,
23 integrity?: string,
24 nonce?: string,
25 + fetchPriority?: 'high' | 'low' | 'auto',
26 };
27
28 export type HostDispatcher = {
packages/react-dom/src/__tests__/ReactDOMFloat-test.js
+199 -2
@@ -3789,6 +3789,7 @@ body {
3789 as: 'style',
3790 crossOrigin: 'use-credentials',
3791 integrity: 'some hash',
3792 + fetchPriority: 'low',
3793 });
3794 return (
3795 <html>
@@ -3909,6 +3910,113 @@ body {
3910 'ReactDOM.preload(): For `href` "foo", The options provided conflict with props on a matching <link rel="stylesheet" ... /> element. When the preload options disagree with the underlying resource it usually means the browser will not be able to use the preload when the resource is fetched, negating any benefit the preload would provide. React will preload the resource using props derived from the resource instead and ignore the options provided to the `ReactDOM.preload()` call. In general, preloading is useful when you expect to render a resource soon but have not yet done so. In this case since the underlying resource was already rendered the preload call may be extraneous. Try removing the call, otherwise try adjusting both the props on the <link rel="stylesheet" ... /> and the options passed to `ReactDOM.preload()` to agree.\n "integrity" missing from options, underlying prop value: "some hash"\n "media" missing from options, underlying prop value: "print"\n "crossOrigin" option value: "use-credentials", missing from underlying props',
3911 ]);
3912 });
3913 +
3914 + it('supports fetchPriority', async () => {
3915 + function Component({isServer}) {
3916 + ReactDOM.preload(isServer ? 'highserver' : 'highclient', {
3917 + as: 'script',
3918 + fetchPriority: 'high',
3919 + });
3920 + ReactDOM.preload(isServer ? 'lowserver' : 'lowclient', {
3921 + as: 'style',
3922 + fetchPriority: 'low',
3923 + });
3924 + ReactDOM.preload(isServer ? 'autoserver' : 'autoclient', {
3925 + as: 'style',
3926 + fetchPriority: 'auto',
3927 + });
3928 + return 'hello';
3929 + }
3930 +
3931 + await act(() => {
3932 + renderToPipeableStream(
3933 + <html>
3934 + <body>
3935 + <Component isServer={true} />
3936 + </body>
3937 + </html>,
3938 + ).pipe(writable);
3939 + });
3940 +
3941 + expect(getMeaningfulChildren(document)).toEqual(
3942 + <html>
3943 + <head>
3944 + <link
3945 + rel="preload"
3946 + as="style"
3947 + href="lowserver"
3948 + fetchpriority="low"
3949 + />
3950 + <link
3951 + rel="preload"
3952 + as="style"
3953 + href="autoserver"
3954 + fetchpriority="auto"
3955 + />
3956 + <link
3957 + rel="preload"
3958 + as="script"
3959 + href="highserver"
3960 + fetchpriority="high"
3961 + />
3962 + </head>
3963 + <body>hello</body>
3964 + </html>,
3965 + );
3966 +
3967 + ReactDOMClient.hydrateRoot(
3968 + document,
3969 + <html>
3970 + <body>
3971 + <Component />
3972 + </body>
3973 + </html>,
3974 + );
3975 + await waitForAll([]);
3976 + expect(getMeaningfulChildren(document)).toEqual(
3977 + <html>
3978 + <head>
3979 + <link
3980 + rel="preload"
3981 + as="style"
3982 + href="lowserver"
3983 + fetchpriority="low"
3984 + />
3985 + <link
3986 + rel="preload"
3987 + as="style"
3988 + href="autoserver"
3989 + fetchpriority="auto"
3990 + />
3991 + <link
3992 + rel="preload"
3993 + as="script"
3994 + href="highserver"
3995 + fetchpriority="high"
3996 + />
3997 + <link
3998 + rel="preload"
3999 + as="script"
4000 + href="highclient"
4001 + fetchpriority="high"
4002 + />
4003 + <link
4004 + rel="preload"
4005 + as="style"
4006 + href="lowclient"
4007 + fetchpriority="low"
4008 + />
4009 + <link
4010 + rel="preload"
4011 + as="style"
4012 + href="autoclient"
4013 + fetchpriority="auto"
4014 + />
4015 + </head>
4016 + <body>hello</body>
4017 + </html>,
4018 + );
4019 + });
4020 });
4021
4022 describe('ReactDOM.preinit(href, { as: ... })', () => {
@@ -4442,7 +4550,6 @@ body {
4550 <body>hello</body>
4551 </html>,
4552 );
4445 -
4553 await clientAct(() => {
4554 ReactDOMClient.hydrateRoot(
4555 document,
@@ -4453,7 +4560,6 @@ body {
4560 </html>,
4561 );
4562 });
4456 -
4563 expect(getMeaningfulChildren(document)).toEqual(
4564 <html>
4565 <head>
@@ -4474,6 +4580,97 @@ body {
4580 </html>,
4581 );
4582 });
4583 +
4584 + it('supports fetchPriority', async () => {
4585 + function Component({isServer}) {
4586 + ReactDOM.preinit(isServer ? 'highserver' : 'highclient', {
4587 + as: 'script',
4588 + fetchPriority: 'high',
4589 + });
4590 + ReactDOM.preinit(isServer ? 'lowserver' : 'lowclient', {
4591 + as: 'style',
4592 + fetchPriority: 'low',
4593 + });
4594 + ReactDOM.preinit(isServer ? 'autoserver' : 'autoclient', {
4595 + as: 'style',
4596 + fetchPriority: 'auto',
4597 + });
4598 + return 'hello';
4599 + }
4600 +
4601 + await act(() => {
4602 + renderToPipeableStream(
4603 + <html>
4604 + <body>
4605 + <Component isServer={true} />
4606 + </body>
4607 + </html>,
4608 + ).pipe(writable);
4609 + });
4610 +
4611 + expect(getMeaningfulChildren(document)).toEqual(
4612 + <html>
4613 + <head>
4614 + <link
4615 + rel="stylesheet"
4616 + href="lowserver"
4617 + fetchpriority="low"
4618 + data-precedence="default"
4619 + />
4620 + <link
4621 + rel="stylesheet"
4622 + href="autoserver"
4623 + fetchpriority="auto"
4624 + data-precedence="default"
4625 + />
4626 + <script async="" src="highserver" fetchpriority="high" />
4627 + </head>
4628 + <body>hello</body>
4629 + </html>,
4630 + );
4631 + ReactDOMClient.hydrateRoot(
4632 + document,
4633 + <html>
4634 + <body>
4635 + <Component />
4636 + </body>
4637 + </html>,
4638 + );
4639 + await waitForAll([]);
4640 + expect(getMeaningfulChildren(document)).toEqual(
4641 + <html>
4642 + <head>
4643 + <link
4644 + rel="stylesheet"
4645 + href="lowserver"
4646 + fetchpriority="low"
4647 + data-precedence="default"
4648 + />
4649 + <link
4650 + rel="stylesheet"
4651 + href="autoserver"
4652 + fetchpriority="auto"
4653 + data-precedence="default"
4654 + />
4655 + <link
4656 + rel="stylesheet"
4657 + href="lowclient"
4658 + fetchpriority="low"
4659 + data-precedence="default"
4660 + />
4661 + <link
4662 + rel="stylesheet"
4663 + href="autoclient"
4664 + fetchpriority="auto"
4665 + data-precedence="default"
4666 + />
4667 + <script async="" src="highserver" fetchpriority="high" />
4668 + <script async="" src="highclient" fetchpriority="high" />
4669 + </head>
4670 + <body>hello</body>
4671 + </html>,
4672 + );
4673 + });
4674 });
4675
4676 describe('Stylesheet Resources', () => {