Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 1 commit into from
Jun 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -2173,6 +2173,7 @@ type PreloadOptions = {
crossOrigin?: string,
integrity?: string,
type?: string,
fetchPriority?: 'high' | 'low' | 'auto',
};
function preload(href: string, options: PreloadOptions) {
if (!enableFloat) {
Expand Down Expand Up @@ -2245,6 +2246,7 @@ function preloadPropsFromPreloadOptions(
crossOrigin: as === 'font' ? '' : options.crossOrigin,
integrity: options.integrity,
type: options.type,
fetchPriority: options.fetchPriority,
};
}

Expand All @@ -2254,6 +2256,7 @@ type PreinitOptions = {
crossOrigin?: string,
integrity?: string,
nonce?: string,
fetchPriority?: 'high' | 'low' | 'auto',
};
function preinit(href: string, options: PreinitOptions) {
if (!enableFloat) {
Expand Down Expand Up @@ -2395,6 +2398,7 @@ function stylesheetPropsFromPreinitOptions(
'data-precedence': precedence,
crossOrigin: options.crossOrigin,
integrity: options.integrity,
fetchPriority: options.fetchPriority,
};
}

Expand All @@ -2408,6 +2412,7 @@ function scriptPropsFromPreinitOptions(
crossOrigin: options.crossOrigin,
integrity: options.integrity,
nonce: options.nonce,
fetchPriority: options.fetchPriority,
};
}

Expand Down
5 changes: 5 additions & 0 deletions packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -5102,6 +5102,7 @@ type PreloadOptions = {
crossOrigin?: string,
integrity?: string,
type?: string,
fetchPriority?: 'high' | 'low' | 'auto',
};
export function preload(href: string, options: PreloadOptions) {
if (!enableFloat) {
Expand Down Expand Up @@ -5247,6 +5248,7 @@ type PreinitOptions = {
crossOrigin?: string,
integrity?: string,
nonce?: string,
fetchPriority?: 'high' | 'low' | 'auto',
};
function preinit(href: string, options: PreinitOptions): void {
if (!enableFloat) {
Expand Down Expand Up @@ -5590,6 +5592,7 @@ function preloadPropsFromPreloadOptions(
crossOrigin: as === 'font' ? '' : options.crossOrigin,
integrity: options.integrity,
type: options.type,
fetchPriority: options.fetchPriority,
};
}

Expand Down Expand Up @@ -5631,6 +5634,7 @@ function stylesheetPropsFromPreinitOptions(
'data-precedence': precedence,
crossOrigin: options.crossOrigin,
integrity: options.integrity,
fetchPriority: options.fetchPriority,
};
}

Expand Down Expand Up @@ -5662,6 +5666,7 @@ function scriptPropsFromPreinitOptions(
crossOrigin: options.crossOrigin,
integrity: options.integrity,
nonce: options.nonce,
fetchPriority: options.fetchPriority,
};
}

Expand Down
2 changes: 2 additions & 0 deletions packages/react-dom/src/ReactDOMDispatcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ export type PreloadOptions = {
crossOrigin?: string,
integrity?: string,
type?: string,
fetchPriority?: 'high' | 'low' | 'auto',
};
export type PreinitOptions = {
as: string,
precedence?: string,
crossOrigin?: string,
integrity?: string,
nonce?: string,
fetchPriority?: 'high' | 'low' | 'auto',
};

export type HostDispatcher = {
Expand Down
201 changes: 199 additions & 2 deletions packages/react-dom/src/__tests__/ReactDOMFloat-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3789,6 +3789,7 @@ body {
as: 'style',
crossOrigin: 'use-credentials',
integrity: 'some hash',
fetchPriority: 'low',
});
return (
<html>
Expand Down Expand Up @@ -3909,6 +3910,113 @@ body {
'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',
]);
});

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(
<html>
<body>
<Component isServer={true} />
</body>
</html>,
).pipe(writable);
});

expect(getMeaningfulChildren(document)).toEqual(
<html>
<head>
<link
rel="preload"
as="style"
href="lowserver"
fetchpriority="low"
/>
<link
rel="preload"
as="style"
href="autoserver"
fetchpriority="auto"
/>
<link
rel="preload"
as="script"
href="highserver"
fetchpriority="high"
/>
</head>
<body>hello</body>
</html>,
);

ReactDOMClient.hydrateRoot(
document,
<html>
<body>
<Component />
</body>
</html>,
);
await waitForAll([]);
expect(getMeaningfulChildren(document)).toEqual(
<html>
<head>
<link
rel="preload"
as="style"
href="lowserver"
fetchpriority="low"
/>
<link
rel="preload"
as="style"
href="autoserver"
fetchpriority="auto"
/>
<link
rel="preload"
as="script"
href="highserver"
fetchpriority="high"
/>
<link
rel="preload"
as="script"
href="highclient"
fetchpriority="high"
/>
<link
rel="preload"
as="style"
href="lowclient"
fetchpriority="low"
/>
<link
rel="preload"
as="style"
href="autoclient"
fetchpriority="auto"
/>
</head>
<body>hello</body>
</html>,
);
});
});

describe('ReactDOM.preinit(href, { as: ... })', () => {
Expand Down Expand Up @@ -4442,7 +4550,6 @@ body {
<body>hello</body>
</html>,
);

await clientAct(() => {
ReactDOMClient.hydrateRoot(
document,
Expand All @@ -4453,7 +4560,6 @@ body {
</html>,
);
});

expect(getMeaningfulChildren(document)).toEqual(
<html>
<head>
Expand All @@ -4474,6 +4580,97 @@ body {
</html>,
);
});

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(
<html>
<body>
<Component isServer={true} />
</body>
</html>,
).pipe(writable);
});

expect(getMeaningfulChildren(document)).toEqual(
<html>
<head>
<link
rel="stylesheet"
href="lowserver"
fetchpriority="low"
data-precedence="default"
/>
<link
rel="stylesheet"
href="autoserver"
fetchpriority="auto"
data-precedence="default"
/>
<script async="" src="highserver" fetchpriority="high" />
</head>
<body>hello</body>
</html>,
);
ReactDOMClient.hydrateRoot(
document,
<html>
<body>
<Component />
</body>
</html>,
);
await waitForAll([]);
expect(getMeaningfulChildren(document)).toEqual(
<html>
<head>
<link
rel="stylesheet"
href="lowserver"
fetchpriority="low"
data-precedence="default"
/>
<link
rel="stylesheet"
href="autoserver"
fetchpriority="auto"
data-precedence="default"
/>
<link
rel="stylesheet"
href="lowclient"
fetchpriority="low"
data-precedence="default"
/>
<link
rel="stylesheet"
href="autoclient"
fetchpriority="auto"
data-precedence="default"
/>
<script async="" src="highserver" fetchpriority="high" />
<script async="" src="highclient" fetchpriority="high" />
</head>
<body>hello</body>
</html>,
);
});
});

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