KEMBAR78
[Flight] Preload <img> and <link> using hints before they're rendered by sebmarkbage · Pull Request #34604 · facebook/react · GitHub
Skip to content

Conversation

sebmarkbage
Copy link
Collaborator

@sebmarkbage sebmarkbage commented Sep 26, 2025

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>.

@meta-cla meta-cla bot added the CLA Signed label Sep 26, 2025
@github-actions github-actions bot added the React Core Team Opened by a member of the React Core Team label Sep 26, 2025
@react-sizebot
Copy link

react-sizebot commented Sep 26, 2025

Comparing: 250f1b2...b1636f3

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.js = 6.68 kB 6.68 kB +0.05% 1.83 kB 1.83 kB
oss-stable/react-dom/cjs/react-dom-client.production.js = 534.43 kB 534.43 kB = 94.33 kB 94.33 kB
oss-experimental/react-dom/cjs/react-dom.production.js = 6.69 kB 6.69 kB +0.05% 1.83 kB 1.83 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js = 663.69 kB 663.69 kB = 117.00 kB 117.00 kB
facebook-www/ReactDOM-prod.classic.js = 687.59 kB 687.59 kB = 121.04 kB 121.04 kB
facebook-www/ReactDOM-prod.modern.js = 678.02 kB 678.02 kB = 119.39 kB 119.40 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-server.browser.production.js +3.58% 89.08 kB 92.27 kB +3.29% 18.49 kB 19.10 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-server.browser.production.js +3.58% 89.08 kB 92.27 kB +3.29% 18.49 kB 19.10 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-server.edge.production.js +3.54% 90.28 kB 93.47 kB +3.31% 18.75 kB 19.37 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-server.edge.production.js +3.54% 90.28 kB 93.47 kB +3.31% 18.75 kB 19.37 kB
oss-stable-semver/react-server-dom-esm/cjs/react-server-dom-esm-server.node.production.js +3.45% 92.70 kB 95.89 kB +3.13% 19.25 kB 19.85 kB
oss-stable/react-server-dom-esm/cjs/react-server-dom-esm-server.node.production.js +3.45% 92.70 kB 95.89 kB +3.13% 19.25 kB 19.85 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-server.browser.production.js +3.38% 94.61 kB 97.80 kB +3.10% 19.34 kB 19.94 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-server.edge.production.js +3.33% 95.89 kB 99.09 kB +3.12% 19.61 kB 20.23 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.browser.production.js +3.32% 96.14 kB 99.33 kB +3.10% 19.63 kB 20.24 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.browser.production.js +3.32% 96.14 kB 99.33 kB +3.10% 19.63 kB 20.24 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.production.js +3.31% 96.49 kB 99.69 kB +3.08% 19.72 kB 20.33 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.production.js +3.31% 96.49 kB 99.69 kB +3.08% 19.72 kB 20.33 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.production.js +3.31% 96.62 kB 99.82 kB +3.08% 19.72 kB 20.33 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.production.js +3.31% 96.62 kB 99.82 kB +3.08% 19.72 kB 20.33 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.production.js +3.28% 97.36 kB 100.55 kB +3.06% 19.92 kB 20.53 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.production.js +3.28% 97.36 kB 100.55 kB +3.06% 19.92 kB 20.53 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.production.js +3.28% 97.36 kB 100.55 kB +3.06% 19.92 kB 20.53 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.production.js +3.28% 97.36 kB 100.55 kB +3.06% 19.92 kB 20.53 kB
oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-server.node.production.js +3.25% 98.19 kB 101.39 kB +3.01% 20.14 kB 20.75 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.browser.production.js +3.14% 101.67 kB 104.86 kB +2.94% 20.53 kB 21.13 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.production.js +3.13% 102.02 kB 105.21 kB +2.93% 20.63 kB 21.23 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.production.js +3.13% 102.12 kB 105.31 kB +3.05% 20.57 kB 21.20 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.unbundled.production.js +3.11% 102.70 kB 105.89 kB +2.99% 20.69 kB 21.31 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.unbundled.production.js +3.11% 102.70 kB 105.89 kB +2.99% 20.69 kB 21.31 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.production.js +3.10% 102.97 kB 106.17 kB +2.91% 20.85 kB 21.45 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.production.js +3.10% 102.97 kB 106.17 kB +2.91% 20.84 kB 21.45 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.production.js +3.08% 103.75 kB 106.94 kB +2.95% 20.90 kB 21.52 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.production.js +3.08% 103.75 kB 106.94 kB +2.95% 20.90 kB 21.52 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.production.js +3.08% 103.77 kB 106.97 kB +2.95% 20.91 kB 21.53 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.production.js +3.08% 103.77 kB 106.97 kB +2.95% 20.91 kB 21.53 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.unbundled.production.js +2.95% 108.19 kB 111.39 kB +2.81% 21.62 kB 22.23 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.production.js +2.92% 109.25 kB 112.44 kB +2.77% 21.84 kB 22.45 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.production.js +2.92% 109.27 kB 112.46 kB +2.78% 21.85 kB 22.45 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-server.browser.development.js +2.12% 178.51 kB 182.30 kB +2.28% 32.48 kB 33.22 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-server.browser.development.js +2.12% 178.51 kB 182.30 kB +2.28% 32.48 kB 33.22 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-server.edge.development.js +2.08% 182.24 kB 186.03 kB +2.19% 32.99 kB 33.71 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-server.edge.development.js +2.08% 182.24 kB 186.03 kB +2.19% 32.99 kB 33.71 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.browser.development.js +2.03% 186.36 kB 190.15 kB +2.25% 33.82 kB 34.58 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.browser.development.js +2.03% 186.36 kB 190.15 kB +2.25% 33.82 kB 34.58 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-server.browser.development.js +2.03% 186.09 kB 189.87 kB +2.32% 33.67 kB 34.46 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.development.js +2.03% 186.83 kB 190.62 kB +2.27% 33.91 kB 34.68 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.development.js +2.03% 186.83 kB 190.62 kB +2.27% 33.91 kB 34.68 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-server.browser.production.js +3.58% 89.08 kB 92.27 kB +3.29% 18.49 kB 19.10 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-server.browser.production.js +3.58% 89.08 kB 92.27 kB +3.29% 18.49 kB 19.10 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-server.edge.production.js +3.54% 90.28 kB 93.47 kB +3.31% 18.75 kB 19.37 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-server.edge.production.js +3.54% 90.28 kB 93.47 kB +3.31% 18.75 kB 19.37 kB
oss-stable-semver/react-server-dom-esm/cjs/react-server-dom-esm-server.node.production.js +3.45% 92.70 kB 95.89 kB +3.13% 19.25 kB 19.85 kB
oss-stable/react-server-dom-esm/cjs/react-server-dom-esm-server.node.production.js +3.45% 92.70 kB 95.89 kB +3.13% 19.25 kB 19.85 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-server.browser.production.js +3.38% 94.61 kB 97.80 kB +3.10% 19.34 kB 19.94 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-server.edge.production.js +3.33% 95.89 kB 99.09 kB +3.12% 19.61 kB 20.23 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.browser.production.js +3.32% 96.14 kB 99.33 kB +3.10% 19.63 kB 20.24 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.browser.production.js +3.32% 96.14 kB 99.33 kB +3.10% 19.63 kB 20.24 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.production.js +3.31% 96.49 kB 99.69 kB +3.08% 19.72 kB 20.33 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.production.js +3.31% 96.49 kB 99.69 kB +3.08% 19.72 kB 20.33 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.production.js +3.31% 96.62 kB 99.82 kB +3.08% 19.72 kB 20.33 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.production.js +3.31% 96.62 kB 99.82 kB +3.08% 19.72 kB 20.33 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.production.js +3.28% 97.36 kB 100.55 kB +3.06% 19.92 kB 20.53 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.production.js +3.28% 97.36 kB 100.55 kB +3.06% 19.92 kB 20.53 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.production.js +3.28% 97.36 kB 100.55 kB +3.06% 19.92 kB 20.53 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.production.js +3.28% 97.36 kB 100.55 kB +3.06% 19.92 kB 20.53 kB
oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-server.node.production.js +3.25% 98.19 kB 101.39 kB +3.01% 20.14 kB 20.75 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.browser.production.js +3.14% 101.67 kB 104.86 kB +2.94% 20.53 kB 21.13 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.production.js +3.13% 102.02 kB 105.21 kB +2.93% 20.63 kB 21.23 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.production.js +3.13% 102.12 kB 105.31 kB +3.05% 20.57 kB 21.20 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.unbundled.production.js +3.11% 102.70 kB 105.89 kB +2.99% 20.69 kB 21.31 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.unbundled.production.js +3.11% 102.70 kB 105.89 kB +2.99% 20.69 kB 21.31 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.production.js +3.10% 102.97 kB 106.17 kB +2.91% 20.85 kB 21.45 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.production.js +3.10% 102.97 kB 106.17 kB +2.91% 20.84 kB 21.45 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.production.js +3.08% 103.75 kB 106.94 kB +2.95% 20.90 kB 21.52 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.production.js +3.08% 103.75 kB 106.94 kB +2.95% 20.90 kB 21.52 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.production.js +3.08% 103.77 kB 106.97 kB +2.95% 20.91 kB 21.53 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.production.js +3.08% 103.77 kB 106.97 kB +2.95% 20.91 kB 21.53 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.unbundled.production.js +2.95% 108.19 kB 111.39 kB +2.81% 21.62 kB 22.23 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.production.js +2.92% 109.25 kB 112.44 kB +2.77% 21.84 kB 22.45 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.production.js +2.92% 109.27 kB 112.46 kB +2.78% 21.85 kB 22.45 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-server.browser.development.js +2.12% 178.51 kB 182.30 kB +2.28% 32.48 kB 33.22 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-server.browser.development.js +2.12% 178.51 kB 182.30 kB +2.28% 32.48 kB 33.22 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-server.edge.development.js +2.08% 182.24 kB 186.03 kB +2.19% 32.99 kB 33.71 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-server.edge.development.js +2.08% 182.24 kB 186.03 kB +2.19% 32.99 kB 33.71 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.browser.development.js +2.03% 186.36 kB 190.15 kB +2.25% 33.82 kB 34.58 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.browser.development.js +2.03% 186.36 kB 190.15 kB +2.25% 33.82 kB 34.58 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-server.browser.development.js +2.03% 186.09 kB 189.87 kB +2.32% 33.67 kB 34.46 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.development.js +2.03% 186.83 kB 190.62 kB +2.27% 33.91 kB 34.68 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.development.js +2.03% 186.83 kB 190.62 kB +2.27% 33.91 kB 34.68 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js +1.99% 190.12 kB 193.91 kB +2.25% 34.31 kB 35.08 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js +1.99% 190.12 kB 193.91 kB +2.25% 34.31 kB 35.08 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.development.js +1.99% 190.12 kB 193.91 kB +2.25% 34.32 kB 35.09 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.development.js +1.99% 190.12 kB 193.91 kB +2.25% 34.32 kB 35.09 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-server.edge.development.js +1.99% 190.17 kB 193.95 kB +2.26% 34.26 kB 35.04 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.browser.development.js +1.95% 193.93 kB 197.72 kB +2.19% 35.05 kB 35.82 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.development.js +1.95% 194.40 kB 198.19 kB +2.19% 35.15 kB 35.92 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js +1.91% 198.05 kB 201.83 kB +2.15% 35.62 kB 36.38 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.development.js +1.91% 198.05 kB 201.84 kB +2.14% 35.62 kB 36.38 kB
oss-stable-semver/react-server-dom-esm/cjs/react-server-dom-esm-server.node.development.js +1.87% 202.88 kB 206.67 kB +1.96% 37.07 kB 37.80 kB
oss-stable/react-server-dom-esm/cjs/react-server-dom-esm-server.node.development.js +1.87% 202.88 kB 206.67 kB +1.96% 37.07 kB 37.80 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.development.js +1.81% 209.38 kB 213.17 kB +1.95% 37.75 kB 38.49 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.development.js +1.81% 209.38 kB 213.17 kB +1.95% 37.75 kB 38.49 kB
oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-server.node.development.js +1.80% 210.43 kB 214.22 kB +1.95% 38.33 kB 39.08 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.unbundled.development.js +1.75% 216.11 kB 219.90 kB +1.95% 38.85 kB 39.61 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.unbundled.development.js +1.75% 216.11 kB 219.90 kB +1.95% 38.85 kB 39.61 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.development.js +1.75% 216.93 kB 220.72 kB +1.92% 39.00 kB 39.75 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js +1.74% 217.32 kB 221.11 kB +1.94% 39.14 kB 39.90 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js +1.74% 217.32 kB 221.11 kB +1.94% 39.14 kB 39.90 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.development.js +1.74% 217.37 kB 221.16 kB +1.93% 39.15 kB 39.91 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.development.js +1.74% 217.37 kB 221.16 kB +1.93% 39.15 kB 39.91 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.unbundled.development.js +1.69% 223.66 kB 227.45 kB +1.87% 40.09 kB 40.84 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js +1.68% 224.87 kB 228.66 kB +1.85% 40.39 kB 41.14 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.development.js +1.68% 224.92 kB 228.71 kB +1.84% 40.40 kB 41.14 kB

Generated by 🚫 dangerJS against b1636f3

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.
Co-authored-by: Josh Story <josh.c.story@gmail.com>
@sebmarkbage sebmarkbage merged commit 047715c into facebook:main Sep 26, 2025
14 of 16 checks passed
github-actions bot pushed a commit to code/lib-react that referenced this pull request Sep 27, 2025
…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)
github-actions bot pushed a commit to code/lib-react that referenced this pull request Sep 27, 2025
…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)
EugeneChoi4 pushed a commit to EugeneChoi4/react that referenced this pull request Sep 29, 2025
…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', {

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

Suggested change
preload(href, 'stylesheet', {
preload(href, 'style', {

vercel/next.js#84569

Copy link
Collaborator

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.

unstubbable added a commit to unstubbable/react that referenced this pull request Oct 7, 2025
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
unstubbable added a commit that referenced this pull request Oct 10, 2025
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed React Core Team Opened by a member of the React Core Team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants