-
Notifications
You must be signed in to change notification settings - Fork 49.6k
[Flight] Preload <img> and <link> using hints before they're rendered #34604
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
Conversation
4a40cad
to
c406d46
Compare
This includes all resources. Not just hoistable and not just suspensey CSS since they will all start loading early regardless of where they are in the viewport anyway.
c406d46
to
05137bb
Compare
packages/react-dom-bindings/src/server/ReactFlightServerConfigDOM.js
Outdated
Show resolved
Hide resolved
…facebook#34604) In Fizz and Fiber we emit hints for suspensey images and CSS as soon as we discover them during render. At the beginning of the stream. This adds a similar capability when a Host Component is known to be a Host Component during the Flight render. The client doesn't know that these resources are in the payload until it parses that particular component which is lazy. So they need to be hoisted with hints. We detect when these are rendered during Flight and add them as hints. That allows you to consume a Flight payload to preload prefetched content without having to render it. `<link rel="preload">` can be hoisted more or less as is. `<link rel="stylesheet">` we preload but we don't actually insert them anywhere until they're rendered. We do these even for non-suspensey stylesheets since we know that when they're rendered they're going to start loading even if they're not immediately used. They're never lazy. `<img src>` we only preload if they follow the suspensey image pattern since otherwise they may be more lazy e.g. by if they're in the viewport. We also skip if they're known to be inside `<picture>`. Same as Fizz. Ideally this would preload the other `<source>` but it's tricky. The downside of this is that you might conditionally render something in only one branch given a client component. However, in that case you're already eagerly fetching the server component's data in that branch so it's not too much of a stretch that you want to eagerly fetch the corresponding resources as well. If you wanted it to be lazy, you should've done a lazy fetch of the RSC. We don't collect hints when any of these are wrapped in a Client Component. In those cases you might want to add your own preload to a wrapper Shared Component. Everything is skipped if it's known to be inside `<noscript>`. Note that the format context is approximate (see facebook#34601) so it's possible for these hints to overfetch or underfetch if you try to trick it. E.g. by rendering Server Components inside a Client Component that renders `<noscript>`. --------- Co-authored-by: Josh Story <josh.c.story@gmail.com> DiffTrain build for [047715c](facebook@047715c)
…facebook#34604) In Fizz and Fiber we emit hints for suspensey images and CSS as soon as we discover them during render. At the beginning of the stream. This adds a similar capability when a Host Component is known to be a Host Component during the Flight render. The client doesn't know that these resources are in the payload until it parses that particular component which is lazy. So they need to be hoisted with hints. We detect when these are rendered during Flight and add them as hints. That allows you to consume a Flight payload to preload prefetched content without having to render it. `<link rel="preload">` can be hoisted more or less as is. `<link rel="stylesheet">` we preload but we don't actually insert them anywhere until they're rendered. We do these even for non-suspensey stylesheets since we know that when they're rendered they're going to start loading even if they're not immediately used. They're never lazy. `<img src>` we only preload if they follow the suspensey image pattern since otherwise they may be more lazy e.g. by if they're in the viewport. We also skip if they're known to be inside `<picture>`. Same as Fizz. Ideally this would preload the other `<source>` but it's tricky. The downside of this is that you might conditionally render something in only one branch given a client component. However, in that case you're already eagerly fetching the server component's data in that branch so it's not too much of a stretch that you want to eagerly fetch the corresponding resources as well. If you wanted it to be lazy, you should've done a lazy fetch of the RSC. We don't collect hints when any of these are wrapped in a Client Component. In those cases you might want to add your own preload to a wrapper Shared Component. Everything is skipped if it's known to be inside `<noscript>`. Note that the format context is approximate (see facebook#34601) so it's possible for these hints to overfetch or underfetch if you try to trick it. E.g. by rendering Server Components inside a Client Component that renders `<noscript>`. --------- Co-authored-by: Josh Story <josh.c.story@gmail.com> DiffTrain build for [047715c](facebook@047715c)
…facebook#34604) In Fizz and Fiber we emit hints for suspensey images and CSS as soon as we discover them during render. At the beginning of the stream. This adds a similar capability when a Host Component is known to be a Host Component during the Flight render. The client doesn't know that these resources are in the payload until it parses that particular component which is lazy. So they need to be hoisted with hints. We detect when these are rendered during Flight and add them as hints. That allows you to consume a Flight payload to preload prefetched content without having to render it. `<link rel="preload">` can be hoisted more or less as is. `<link rel="stylesheet">` we preload but we don't actually insert them anywhere until they're rendered. We do these even for non-suspensey stylesheets since we know that when they're rendered they're going to start loading even if they're not immediately used. They're never lazy. `<img src>` we only preload if they follow the suspensey image pattern since otherwise they may be more lazy e.g. by if they're in the viewport. We also skip if they're known to be inside `<picture>`. Same as Fizz. Ideally this would preload the other `<source>` but it's tricky. The downside of this is that you might conditionally render something in only one branch given a client component. However, in that case you're already eagerly fetching the server component's data in that branch so it's not too much of a stretch that you want to eagerly fetch the corresponding resources as well. If you wanted it to be lazy, you should've done a lazy fetch of the RSC. We don't collect hints when any of these are wrapped in a Client Component. In those cases you might want to add your own preload to a wrapper Shared Component. Everything is skipped if it's known to be inside `<noscript>`. Note that the format context is approximate (see facebook#34601) so it's possible for these hints to overfetch or underfetch if you try to trick it. E.g. by rendering Server Components inside a Client Component that renders `<noscript>`. --------- Co-authored-by: Josh Story <josh.c.story@gmail.com>
return; | ||
} | ||
case 'stylesheet': { | ||
preload(href, 'stylesheet', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The stylesheet
value used here is incorrect. It should be style
.
https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/preload#what_types_of_content_can_be_preloaded
preload(href, 'stylesheet', { | |
preload(href, 'style', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the report. Fixed in #34760.
Follow-up to facebook#34604. For a stylesheet, we need to render `<link rel="preload" as="style" ...>`, and not `<link rel="preload" as="stylesheet" ...>`. ([ref](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/preload#what_types_of_content_can_be_preloaded)) fixes vercel/next.js#84569
Follow-up to #34604. For a stylesheet, we need to render `<link rel="preload" as="style" ...>`, and not `<link rel="preload" as="stylesheet" ...>`. ([ref](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/preload#what_types_of_content_can_be_preloaded)) fixes vercel/next.js#84569
In Fizz and Fiber we emit hints for suspensey images and CSS as soon as we discover them during render. At the beginning of the stream. This adds a similar capability when a Host Component is known to be a Host Component during the Flight render.
The client doesn't know that these resources are in the payload until it parses that particular component which is lazy. So they need to be hoisted with hints. We detect when these are rendered during Flight and add them as hints. That allows you to consume a Flight payload to preload prefetched content without having to render it.
<link rel="preload">
can be hoisted more or less as is.<link rel="stylesheet">
we preload but we don't actually insert them anywhere until they're rendered. We do these even for non-suspensey stylesheets since we know that when they're rendered they're going to start loading even if they're not immediately used. They're never lazy.<img src>
we only preload if they follow the suspensey image pattern since otherwise they may be more lazy e.g. by if they're in the viewport. We also skip if they're known to be inside<picture>
. Same as Fizz. Ideally this would preload the other<source>
but it's tricky.The downside of this is that you might conditionally render something in only one branch given a client component. However, in that case you're already eagerly fetching the server component's data in that branch so it's not too much of a stretch that you want to eagerly fetch the corresponding resources as well. If you wanted it to be lazy, you should've done a lazy fetch of the RSC.
We don't collect hints when any of these are wrapped in a Client Component. In those cases you might want to add your own preload to a wrapper Shared Component.
Everything is skipped if it's known to be inside
<noscript>
.Note that the format context is approximate (see #34601) so it's possible for these hints to overfetch or underfetch if you try to trick it. E.g. by rendering Server Components inside a Client Component that renders
<noscript>
.