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

fix(react): dedupe prefetch links #7060

Merged
merged 11 commits into from Aug 9, 2023

Conversation

markdalgleish
Copy link
Member

@markdalgleish markdalgleish commented Aug 4, 2023

Closes #5677

  • Docs
  • Tests

Fixing the linked issue highlighted a number of bugs in the code related to deduping links and generating keys for rendered links. I've added comments below to highlight the notable changes.

@markdalgleish markdalgleish added bug Something isn't working renderer:react v2 Issues related to v2 apis labels Aug 4, 2023
@changeset-bot
Copy link

changeset-bot bot commented Aug 4, 2023

🦋 Changeset detected

Latest commit: ee1a692

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 16 packages
Name Type
@remix-run/react Patch
@remix-run/testing Patch
create-remix Patch
remix Patch
@remix-run/architect Patch
@remix-run/cloudflare Patch
@remix-run/cloudflare-pages Patch
@remix-run/cloudflare-workers Patch
@remix-run/css-bundle Patch
@remix-run/deno Patch
@remix-run/dev Patch
@remix-run/eslint-config Patch
@remix-run/express Patch
@remix-run/node Patch
@remix-run/serve Patch
@remix-run/server-runtime Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@markdalgleish markdalgleish marked this pull request as ready for review August 7, 2023 05:12
@@ -360,7 +360,7 @@ export function Links() {

return (
<link
key={link.rel + (link.href || "") + (imageSrcSet || "")}
key={key}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They key is now the exact same string used for deduping. To enable this, the utilities that return arrays of link descriptors now provide Keyed objects that expose a key property for each link.

This ensures we never get any duplicate key errors, as opposed to the previous logic which could result in duplicate keys if rel, href and/or imageSrcSet properties were the same but other properties differed.

? ({ ...link, rel: "prefetch" } as HtmlLinkDescriptor)
: ({ ...link, rel: "prefetch", as: "style" } as HtmlLinkDescriptor)
);
return dedupeLinkDescriptors(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the core fix for #5677. The prefetch links weren't deduped as they were in getLinksForMatches (now called getKeyedLinksForMatches).

if (!set.has(str)) {
set.add(str);
deduped.push(descriptor);
let key = JSON.stringify(sortKeys(descriptor));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixes an unreported bug where the deduping didn't work correctly if properties were specified in a different order. This behaviour is covered in the newly added test.

let set = new Set();
let preloadsSet = new Set(preloads);

return descriptors.reduce((deduped, descriptor) => {
let alreadyModulePreload =
preloads &&
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the preloads array is now optional, we bail out early if it hasn't been provided.

.filter((link) => link.rel === "stylesheet" || link.rel === "preload")
.map((link) =>
link.rel === "stylesheet"
? ({ ...link, rel: "prefetch", as: "style" } as HtmlLinkDescriptor)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was just a slight refactor for legibility since link.rel === "stylesheet" was checked first in the earlier filter.

// these don't spread `linkProps` because they are full link descriptors
// already with their own props
<link key={link.href} {...link} />
<link key={key} {...link} />
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixes an unreported bug where responsive image prefetch links would all have a key of undefined since they have imgSrcSet and imgSizes properties but no href property.

export async function getStylesheetPrefetchLinks(
export type KeyedHtmlLinkDescriptor = { key: string; link: HtmlLinkDescriptor };

export async function getKeyedPrefetchLinks(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I renamed this from getStylesheetPrefetchLinks to getKeyedPrefetchLinks because, apart from now being an array of objects with key and link properties so consumers don't need to generate their own keys, it also makes it clearer that this code also converts preload links into prefetches (as seen on line 330).

@MichaelDeBoey MichaelDeBoey linked an issue Aug 7, 2023 that may be closed by this pull request
1 task
@markdalgleish markdalgleish self-assigned this Aug 7, 2023
@brophdawg11 brophdawg11 removed their assignment Aug 8, 2023
@markdalgleish markdalgleish merged commit a179aa7 into dev Aug 9, 2023
9 checks passed
@markdalgleish markdalgleish deleted the markdalgleish/dedupe-prefetch-links branch August 9, 2023 00:50
@github-actions github-actions bot added the awaiting release This issue has been fixed and will be released soon label Aug 9, 2023
@github-actions
Copy link
Contributor

github-actions bot commented Aug 9, 2023

🤖 Hello there,

We just published version v0.0.0-nightly-a179aa7-20230809 which includes this pull request. If you'd like to take it for a test run please try it out and let us know what you think!

Thanks!

@github-actions
Copy link
Contributor

🤖 Hello there,

We just published version v0.0.0-nightly-b1149bb-20230810 which includes this pull request. If you'd like to take it for a test run please try it out and let us know what you think!

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting release This issue has been fixed and will be released soon bug Something isn't working CLA Signed renderer:react v2 Issues related to v2 apis
Projects
No open projects
Status: Merged
Development

Successfully merging this pull request may close these issues.

Duplicate children keys in getStylesheetPrefetchLinks
2 participants