Skip to content

Commit

Permalink
Fixes behavior where a preload on the client would only check if the …
Browse files Browse the repository at this point in the history
…preload existed already in the DOM rather than checking if the underlying asset was also already in the dom
  • Loading branch information
gnoff committed Apr 25, 2023
1 parent 21a9390 commit 26e291e
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 3 deletions.
23 changes: 20 additions & 3 deletions packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -2138,8 +2138,12 @@ function preload(href: string, options: PreloadOptions) {
const as = options.as;
const limitedEscapedHref =
escapeSelectorAttributeValueInsideDoubleQuotes(href);
const preloadKey = `link[rel="preload"][as="${as}"][href="${limitedEscapedHref}"]`;
let key = preloadKey;
const preloadSelector = `link[rel="preload"][as="${as}"][href="${limitedEscapedHref}"]`;
// Some preloads are keyed under their selector. This happens when the preload is for
// an arbitrary type. Other preloads are keyed under the resource key they represent a preload for.
// Here we figure out which key to use to determine if we have a preload already.
let key = preloadSelector;
switch (as) {
case 'style':
key = getStyleKey(href);
Expand All @@ -2152,7 +2156,20 @@ function preload(href: string, options: PreloadOptions) {
const preloadProps = preloadPropsFromPreloadOptions(href, as, options);
preloadPropsMap.set(key, preloadProps);
if (null === ownerDocument.querySelector(preloadKey)) {
if (null === ownerDocument.querySelector(preloadSelector)) {
if (
as === 'style' &&
ownerDocument.querySelector(getStylesheetSelectorFromKey(key))
) {
// We already have a stylesheet for this key. We don't need to preload it.
return;
} else if (
as === 'script' &&
ownerDocument.querySelector(getScriptSelectorFromKey(key))
) {
// We already have a stylesheet for this key. We don't need to preload it.
return;
}
const instance = ownerDocument.createElement('link');
setInitialProperties(instance, 'link', preloadProps);
markNodeAsHoistable(instance);
Expand Down
55 changes: 55 additions & 0 deletions packages/react-dom/src/__tests__/ReactDOMFloat-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3496,6 +3496,61 @@ body {
);
});

it('will not insert a preload if the underlying resource already exists in the Document', async () => {
await act(() => {
renderToPipeableStream(
<html>
<head>
<link rel="stylesheet" href="foo" precedence="default" />
<script async={true} src="bar" />
<link rel="preload" href="baz" as="font" />
</head>
<body>
<div id="container" />
</body>
</html>,
).pipe(writable);
});

expect(getMeaningfulChildren(document)).toEqual(
<html>
<head>
<link rel="stylesheet" href="foo" data-precedence="default" />
<script async="" src="bar" />
<link rel="preload" href="baz" as="font" />
</head>
<body>
<div id="container" />
</body>
</html>,
);

container = document.getElementById('container');

function ClientApp() {
ReactDOM.preload('foo', {as: 'style'});
ReactDOM.preload('bar', {as: 'script'});
ReactDOM.preload('baz', {as: 'font'});
return 'foo';
}

const root = ReactDOMClient.createRoot(container);

await clientAct(() => root.render(<ClientApp />));
expect(getMeaningfulChildren(document)).toEqual(
<html>
<head>
<link rel="stylesheet" href="foo" data-precedence="default" />
<script async="" src="bar" />
<link rel="preload" href="baz" as="font" />
</head>
<body>
<div id="container">foo</div>
</body>
</html>,
);
});

describe('ReactDOM.prefetchDNS(href)', () => {
it('creates a dns-prefetch resource when called', async () => {
function App({url}) {
Expand Down

0 comments on commit 26e291e

Please sign in to comment.