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

[Fizz][Float] Only flush Hoistable Elements if their containing Boundary is complete #27534

Closed
wants to merge 2 commits into from

Conversation

gnoff
Copy link
Collaborator

@gnoff gnoff commented Oct 17, 2023

Currently Stacked on: #27742

On the client Hoistable Elements act much like Host Components except they render into the document head instead of in their rendered position. On the server was previously not the case as any rendered hoistable would flush regardless of whether the boundary it was contained within was completed. This was even more egregious with fallbacks where if you rendered a hoistable in a fallback it would flush even if the suspense boundary never actually flushed the fallback because the primary content finished in time.

This change updates the flushing semantics of Hoistable Elements to bring them in line with the client.

What this means is that Hoistables are no longer an avenue to emit things like early preloads because if you do so within a Suspense Boundary the preload won't flush until the boundary completes making the preload likely not very useful. The general idea here is that Hoistables are not meant for things that have support in the imperative Float methods like ReactDOM.preload and ReactDOM.preinit. Given this we are going to simplify the flushing queue ordering to not prioritized any particular hoistables over others.

This PR however does not yet go all the way to a single queue for hoistables. First we have to deal with charset. Our plan is to make this a config or infer it from some encoding parameter passed to the render function. This generally is a better way to model charset since you can't reasonably emit this one late, it's either up front or broken and it's tied to some other aspect of the rendering namely the encoding format (note that for web API environments this may be limited to utf-8 only since TextEncoder can't encode other formats)

This PR also does not remove the privileged flushing for viewport meta tags. This is harder than charset b/c it is reasonably something you (or at least your meta-framework) might render and not know up front when you invoke the render method. If Hoistables have no privileged flushing queues then we need some means to support viewport from the imperative float methods since it emitting first before we flush things like image preloads is necessary for good performance.

This PR also refactors the Resource tracking to follow the patterns established for task local state values. This is a cleaner implementation though not functionally different. The reason this was not originally pursued is the boundary resources at one point were entanged with the Float imperative methods so it needed to be part of the resolvable resources object during dispatch. We've moved away from that by allowing these methods to be called outside of Render and no longer associate anyting to the Boundary state itself so we can not clean up the implementation here a bit.

@facebook-github-bot facebook-github-bot added CLA Signed React Core Team Opened by a member of the React Core Team labels Oct 17, 2023
@@ -671,60 +671,6 @@ describe('ReactDOMFloat', () => {
);
});

// @gate enableFloat
it('emits resources before everything else when rendering with no head', async () => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

These tests weren't actually testing resource flushing order just hoistable order. These tests have been replaced by numerous others that actually cover the specific ordering so I've just removed them

@react-sizebot
Copy link

react-sizebot commented Oct 17, 2023

Comparing: 6c7b41d...6518505

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.min.js = 175.90 kB 175.32 kB = 54.75 kB 54.58 kB
oss-experimental/react-dom/cjs/react-dom.production.min.js = 177.97 kB 177.39 kB = 55.39 kB 55.22 kB
facebook-www/ReactDOM-prod.classic.js = 569.81 kB 568.94 kB = 100.29 kB 100.16 kB
facebook-www/ReactDOM-prod.modern.js = 553.67 kB 553.27 kB = 97.38 kB 97.26 kB
oss-stable-semver/react-server/cjs/react-server.production.min.js +3.02% 34.98 kB 36.04 kB +2.19% 11.21 kB 11.46 kB
oss-stable/react-server/cjs/react-server.production.min.js +3.02% 34.98 kB 36.04 kB +2.19% 11.21 kB 11.46 kB
oss-experimental/react-server/cjs/react-server.production.min.js +2.88% 37.86 kB 38.95 kB +2.28% 11.94 kB 12.21 kB
oss-stable-semver/react-server/cjs/react-server.production.js +2.63% 140.07 kB 143.75 kB +2.45% 32.62 kB 33.41 kB
oss-stable/react-server/cjs/react-server.production.js +2.63% 140.07 kB 143.75 kB +2.45% 32.62 kB 33.41 kB
oss-experimental/react-server/cjs/react-server.production.js +2.48% 150.31 kB 154.03 kB +2.30% 34.45 kB 35.24 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/cjs/react-server.production.min.js +3.02% 34.98 kB 36.04 kB +2.19% 11.21 kB 11.46 kB
oss-stable/react-server/cjs/react-server.production.min.js +3.02% 34.98 kB 36.04 kB +2.19% 11.21 kB 11.46 kB
oss-experimental/react-server/cjs/react-server.production.min.js +2.88% 37.86 kB 38.95 kB +2.28% 11.94 kB 12.21 kB
oss-stable-semver/react-server/cjs/react-server.production.js +2.63% 140.07 kB 143.75 kB +2.45% 32.62 kB 33.41 kB
oss-stable/react-server/cjs/react-server.production.js +2.63% 140.07 kB 143.75 kB +2.45% 32.62 kB 33.41 kB
oss-experimental/react-server/cjs/react-server.production.js +2.48% 150.31 kB 154.03 kB +2.30% 34.45 kB 35.24 kB
facebook-www/ReactDOMServer-prod.modern.js +1.75% 190.03 kB 193.37 kB +1.26% 34.39 kB 34.83 kB
facebook-www/ReactDOMServerStreaming-prod.modern.js +1.73% 193.88 kB 197.23 kB +1.38% 35.52 kB 36.01 kB
facebook-www/ReactDOMServer-prod.classic.js +1.51% 191.91 kB 194.80 kB +1.18% 34.72 kB 35.13 kB
oss-stable-semver/react-server/cjs/react-server.development.js +1.03% 197.81 kB 199.85 kB +1.05% 46.64 kB 47.13 kB
oss-stable/react-server/cjs/react-server.development.js +1.03% 197.81 kB 199.85 kB +1.05% 46.64 kB 47.13 kB
oss-experimental/react-server/cjs/react-server.development.js +1.00% 208.21 kB 210.30 kB +0.97% 48.52 kB 48.99 kB
oss-stable-semver/react-dom/cjs/react-dom-server.bun.production.js +0.93% 300.58 kB 303.38 kB +1.20% 64.85 kB 65.62 kB
oss-stable/react-dom/cjs/react-dom-server.bun.production.js +0.93% 300.61 kB 303.41 kB +1.20% 64.87 kB 65.65 kB
oss-stable-semver/react-dom/cjs/react-dom-server.browser.production.js +0.93% 302.09 kB 304.89 kB +1.15% 65.63 kB 66.38 kB
oss-stable/react-dom/cjs/react-dom-server.browser.production.js +0.93% 302.12 kB 304.92 kB +1.15% 65.65 kB 66.41 kB
oss-stable-semver/react-dom/cjs/react-dom-server.node.production.js +0.92% 304.74 kB 307.54 kB +1.19% 65.62 kB 66.40 kB
oss-stable/react-dom/cjs/react-dom-server.node.production.js +0.92% 304.77 kB 307.57 kB +1.19% 65.64 kB 66.43 kB
oss-experimental/react-noop-renderer/cjs/react-noop-renderer-server.development.js +0.92% 6.34 kB 6.39 kB +0.06% 1.73 kB 1.73 kB
oss-stable-semver/react-noop-renderer/cjs/react-noop-renderer-server.development.js +0.92% 6.34 kB 6.39 kB +0.06% 1.73 kB 1.73 kB
oss-stable/react-noop-renderer/cjs/react-noop-renderer-server.development.js +0.92% 6.34 kB 6.39 kB +0.06% 1.73 kB 1.73 kB
oss-experimental/react-dom/cjs/react-dom-server.bun.production.js +0.91% 311.41 kB 314.26 kB +1.13% 66.82 kB 67.58 kB
oss-stable-semver/react-dom/cjs/react-dom-server.edge.production.js +0.91% 306.37 kB 309.17 kB +1.16% 66.89 kB 67.67 kB
oss-stable/react-dom/cjs/react-dom-server.edge.production.js +0.91% 306.40 kB 309.20 kB +1.16% 66.92 kB 67.69 kB
oss-experimental/react-dom/cjs/react-dom-server.browser.production.js +0.91% 321.87 kB 324.81 kB +1.14% 68.37 kB 69.15 kB
oss-experimental/react-dom/cjs/react-dom-server.node.production.js +0.91% 324.29 kB 327.23 kB +1.14% 68.80 kB 69.58 kB
oss-experimental/react-dom/cjs/react-dom-server.edge.production.js +0.90% 326.45 kB 329.39 kB +1.11% 69.78 kB 70.56 kB
oss-stable-semver/react-dom/cjs/react-dom-server-legacy.browser.production.js +0.84% 302.69 kB 305.24 kB +1.08% 65.49 kB 66.20 kB
oss-stable/react-dom/cjs/react-dom-server-legacy.browser.production.js +0.84% 302.71 kB 305.27 kB +1.08% 65.52 kB 66.23 kB
oss-experimental/react-dom/cjs/react-dom-server-legacy.browser.production.js +0.83% 313.21 kB 315.81 kB +1.07% 67.29 kB 68.02 kB
oss-stable-semver/react-dom/cjs/react-dom-server-legacy.node.production.js +0.83% 308.63 kB 311.18 kB +1.08% 67.21 kB 67.94 kB
oss-stable/react-dom/cjs/react-dom-server-legacy.node.production.js +0.83% 308.66 kB 311.21 kB +1.09% 67.24 kB 67.97 kB
oss-experimental/react-dom/cjs/react-dom-server-legacy.node.production.js +0.81% 319.46 kB 322.06 kB +1.05% 69.17 kB 69.89 kB
oss-experimental/react-noop-renderer/cjs/react-noop-renderer-server.production.js +0.81% 5.92 kB 5.97 kB +0.06% 1.68 kB 1.68 kB
oss-stable-semver/react-noop-renderer/cjs/react-noop-renderer-server.production.js +0.81% 5.92 kB 5.97 kB +0.06% 1.68 kB 1.68 kB
oss-stable/react-noop-renderer/cjs/react-noop-renderer-server.production.js +0.81% 5.92 kB 5.97 kB +0.06% 1.68 kB 1.68 kB
oss-experimental/react-dom/cjs/react-dom-server.browser.production.min.js +0.65% 84.05 kB 84.60 kB +0.70% 25.73 kB 25.91 kB
oss-experimental/react-dom/umd/react-dom-server.browser.production.min.js +0.65% 84.13 kB 84.67 kB +0.60% 26.07 kB 26.22 kB
oss-experimental/react-dom/umd/react-dom-server-legacy.browser.production.min.js +0.62% 79.68 kB 80.18 kB +0.91% 24.53 kB 24.75 kB
oss-experimental/react-dom/cjs/react-dom-server-legacy.browser.production.min.js +0.62% 79.59 kB 80.09 kB +0.89% 24.15 kB 24.37 kB
oss-experimental/react-dom/cjs/react-dom-server.node.production.min.js +0.62% 87.69 kB 88.24 kB +1.02% 26.55 kB 26.82 kB
oss-experimental/react-dom/cjs/react-dom-server.bun.production.min.js +0.62% 82.53 kB 83.04 kB +0.88% 24.88 kB 25.10 kB
oss-experimental/react-dom/cjs/react-dom-server.edge.production.min.js +0.61% 89.47 kB 90.01 kB +0.81% 27.42 kB 27.64 kB
oss-stable-semver/react-dom/umd/react-dom-server.browser.production.min.js +0.60% 77.97 kB 78.44 kB +0.81% 24.60 kB 24.79 kB
oss-stable/react-dom/umd/react-dom-server.browser.production.min.js +0.60% 78.00 kB 78.47 kB +0.82% 24.62 kB 24.82 kB
oss-stable-semver/react-dom/cjs/react-dom-server.browser.production.min.js +0.59% 77.89 kB 78.35 kB +0.75% 24.22 kB 24.40 kB
oss-stable/react-dom/cjs/react-dom-server.browser.production.min.js +0.59% 77.91 kB 78.38 kB +0.75% 24.24 kB 24.42 kB
oss-stable-semver/react-dom/umd/react-dom-server-legacy.browser.production.min.js +0.59% 77.02 kB 77.47 kB +0.85% 23.76 kB 23.96 kB
oss-stable/react-dom/umd/react-dom-server-legacy.browser.production.min.js +0.59% 77.05 kB 77.50 kB +0.85% 23.78 kB 23.98 kB
oss-stable-semver/react-dom/cjs/react-dom-server.bun.production.min.js +0.58% 79.50 kB 79.97 kB +0.80% 24.07 kB 24.26 kB
oss-stable-semver/react-dom/cjs/react-dom-server-legacy.browser.production.min.js +0.58% 76.93 kB 77.37 kB +0.92% 23.39 kB 23.60 kB
oss-stable/react-dom/cjs/react-dom-server.bun.production.min.js +0.58% 79.53 kB 79.99 kB +0.81% 24.09 kB 24.29 kB
oss-stable/react-dom/cjs/react-dom-server-legacy.browser.production.min.js +0.58% 76.95 kB 77.40 kB +0.93% 23.41 kB 23.63 kB
oss-experimental/react-dom/cjs/react-dom-server-legacy.node.production.min.js +0.58% 85.56 kB 86.06 kB +0.83% 26.10 kB 26.31 kB
oss-stable-semver/react-dom/cjs/react-dom-server.node.production.min.js +0.57% 81.09 kB 81.55 kB +0.98% 24.95 kB 25.19 kB
oss-stable/react-dom/cjs/react-dom-server.node.production.min.js +0.57% 81.11 kB 81.58 kB +0.94% 24.98 kB 25.21 kB
oss-stable-semver/react-dom/cjs/react-dom-server.edge.production.min.js +0.56% 82.96 kB 83.42 kB +0.80% 25.83 kB 26.03 kB
oss-stable/react-dom/cjs/react-dom-server.edge.production.min.js +0.56% 82.99 kB 83.45 kB +0.81% 25.85 kB 26.06 kB
oss-stable-semver/react-dom/cjs/react-dom-server-legacy.node.production.min.js +0.55% 82.54 kB 82.99 kB +0.86% 25.25 kB 25.47 kB
oss-stable/react-dom/cjs/react-dom-server-legacy.node.production.min.js +0.55% 82.57 kB 83.02 kB +0.87% 25.27 kB 25.49 kB
oss-experimental/react-noop-renderer/cjs/react-noop-renderer-server.production.min.js +0.50% 3.23 kB 3.24 kB = 1.21 kB 1.20 kB
oss-stable-semver/react-noop-renderer/cjs/react-noop-renderer-server.production.min.js +0.50% 3.23 kB 3.24 kB = 1.21 kB 1.20 kB
oss-stable/react-noop-renderer/cjs/react-noop-renderer-server.production.min.js +0.50% 3.23 kB 3.24 kB = 1.21 kB 1.20 kB
facebook-www/ReactDOMServerStreaming-dev.modern.js +0.47% 464.83 kB 467.01 kB +0.70% 94.50 kB 95.16 kB
facebook-www/ReactDOMServer-dev.classic.js +0.42% 480.63 kB 482.63 kB +0.63% 97.80 kB 98.42 kB
facebook-www/ReactDOMServer-dev.modern.js +0.41% 472.17 kB 474.09 kB +0.63% 96.14 kB 96.75 kB
oss-experimental/react-dom/cjs/react-dom-server.node.development.js +0.30% 437.34 kB 438.65 kB +0.49% 96.71 kB 97.18 kB
oss-experimental/react-dom/cjs/react-dom-server.browser.development.js +0.30% 438.91 kB 440.22 kB +0.49% 97.49 kB 97.97 kB
oss-experimental/react-dom/cjs/react-dom-server.edge.development.js +0.30% 439.50 kB 440.81 kB +0.50% 97.62 kB 98.11 kB
oss-experimental/react-dom/umd/react-dom-server.browser.development.js +0.29% 459.41 kB 460.75 kB +0.49% 98.51 kB 98.99 kB
oss-experimental/react-dom/cjs/react-dom-server.bun.development.js +0.28% 423.77 kB 424.98 kB +0.52% 94.37 kB 94.85 kB
oss-stable-semver/react-dom/cjs/react-dom-server.bun.development.js +0.28% 412.08 kB 413.24 kB +0.54% 92.20 kB 92.70 kB
oss-stable/react-dom/cjs/react-dom-server.bun.development.js +0.28% 412.11 kB 413.27 kB +0.54% 92.23 kB 92.72 kB
oss-stable-semver/react-dom/cjs/react-dom-server.node.development.js +0.28% 416.89 kB 418.05 kB +0.53% 93.28 kB 93.78 kB
oss-stable/react-dom/cjs/react-dom-server.node.development.js +0.28% 416.91 kB 418.07 kB +0.53% 93.31 kB 93.81 kB
oss-stable-semver/react-dom/cjs/react-dom-server.browser.development.js +0.28% 417.92 kB 419.08 kB +0.53% 94.34 kB 94.84 kB
oss-stable/react-dom/cjs/react-dom-server.browser.development.js +0.28% 417.95 kB 419.11 kB +0.53% 94.36 kB 94.86 kB
oss-stable-semver/react-dom/cjs/react-dom-server.edge.development.js +0.28% 418.51 kB 419.67 kB +0.54% 94.47 kB 94.98 kB
oss-stable/react-dom/cjs/react-dom-server.edge.development.js +0.28% 418.54 kB 419.70 kB +0.53% 94.50 kB 95.00 kB
oss-stable-semver/react-dom/umd/react-dom-server.browser.development.js +0.27% 437.52 kB 438.70 kB +0.52% 95.36 kB 95.85 kB
oss-stable/react-dom/umd/react-dom-server.browser.development.js +0.27% 437.54 kB 438.73 kB +0.52% 95.38 kB 95.88 kB
oss-experimental/react-dom/cjs/react-dom-server-legacy.browser.development.js +0.22% 430.18 kB 431.14 kB +0.47% 96.35 kB 96.80 kB
oss-experimental/react-dom/cjs/react-dom-server-legacy.node.development.js +0.22% 432.04 kB 432.99 kB +0.47% 96.81 kB 97.27 kB
oss-stable-semver/react-dom/cjs/react-dom-server-legacy.browser.development.js +0.22% 418.49 kB 419.40 kB +0.49% 94.18 kB 94.64 kB
oss-stable/react-dom/cjs/react-dom-server-legacy.browser.development.js +0.22% 418.52 kB 419.43 kB +0.49% 94.20 kB 94.67 kB
oss-stable-semver/react-dom/cjs/react-dom-server-legacy.node.development.js +0.22% 420.35 kB 421.26 kB +0.49% 94.64 kB 95.10 kB
oss-stable/react-dom/cjs/react-dom-server-legacy.node.development.js +0.22% 420.37 kB 421.28 kB +0.49% 94.67 kB 95.13 kB
oss-experimental/react-dom/umd/react-dom-server-legacy.browser.development.js +0.22% 450.28 kB 451.26 kB +0.43% 97.36 kB 97.78 kB
oss-stable-semver/react-dom/umd/react-dom-server-legacy.browser.development.js +0.21% 438.10 kB 439.03 kB +0.47% 95.19 kB 95.64 kB
oss-stable/react-dom/umd/react-dom-server-legacy.browser.development.js +0.21% 438.13 kB 439.05 kB +0.47% 95.22 kB 95.66 kB
facebook-www/ReactART-prod.classic.js = 351.09 kB 350.32 kB = 59.61 kB 59.54 kB
facebook-www/ReactDOMTesting-dev.modern.js = 1,606.09 kB 1,602.48 kB = 319.46 kB 318.83 kB
facebook-www/ReactDOM-dev.modern.js = 1,585.09 kB 1,581.48 kB = 314.93 kB 314.29 kB
facebook-www/ReactDOMTesting-dev.classic.js = 1,637.68 kB 1,633.88 kB = 325.20 kB 324.58 kB
facebook-www/ReactDOM-dev.classic.js = 1,616.68 kB 1,612.88 kB = 320.69 kB 320.05 kB
oss-experimental/react-dom/cjs/react-dom-unstable_testing.production.min.js = 184.20 kB 183.62 kB = 57.76 kB 57.58 kB
oss-experimental/react-dom/cjs/react-dom.profiling.min.js = 187.44 kB 186.85 kB = 57.72 kB 57.57 kB
oss-experimental/react-dom/umd/react-dom.profiling.min.js = 186.73 kB 186.14 kB = 57.97 kB 57.78 kB
oss-stable/react-dom/cjs/react-dom.profiling.min.js = 185.37 kB 184.78 kB = 57.10 kB 56.95 kB
oss-stable-semver/react-dom/cjs/react-dom.profiling.min.js = 185.30 kB 184.71 kB = 57.08 kB 56.92 kB
oss-stable/react-dom/umd/react-dom.profiling.min.js = 184.67 kB 184.08 kB = 57.34 kB 57.18 kB
oss-stable-semver/react-dom/umd/react-dom.profiling.min.js = 184.60 kB 184.00 kB = 57.32 kB 57.16 kB
oss-experimental/react-dom/cjs/react-dom-unstable_testing.production.js = 969.55 kB 966.43 kB = 217.54 kB 217.02 kB
oss-experimental/react-dom/cjs/react-dom.production.min.js = 177.97 kB 177.39 kB = 55.39 kB 55.22 kB
oss-experimental/react-dom/umd/react-dom.production.min.js = 177.70 kB 177.12 kB = 55.63 kB 55.42 kB
oss-experimental/react-dom/cjs/react-dom.profiling.js = 993.24 kB 989.99 kB = 220.56 kB 220.03 kB
oss-experimental/react-dom/cjs/react-dom.production.js = 951.45 kB 948.33 kB = 213.03 kB 212.51 kB
oss-stable/react-dom/cjs/react-dom.production.min.js = 175.90 kB 175.32 kB = 54.75 kB 54.58 kB
oss-stable-semver/react-dom/cjs/react-dom.production.min.js = 175.83 kB 175.25 kB = 54.73 kB 54.55 kB
oss-stable/react-dom/umd/react-dom.production.min.js = 175.64 kB 175.07 kB = 55.01 kB 54.81 kB
oss-stable-semver/react-dom/umd/react-dom.production.min.js = 175.57 kB 174.99 kB = 54.98 kB 54.78 kB
oss-stable/react-dom/cjs/react-dom.profiling.js = 985.39 kB 982.14 kB = 218.83 kB 218.28 kB
oss-stable-semver/react-dom/cjs/react-dom.profiling.js = 985.37 kB 982.11 kB = 218.80 kB 218.25 kB
oss-stable/react-dom/cjs/react-dom.production.js = 943.60 kB 940.48 kB = 211.33 kB 210.66 kB
oss-stable-semver/react-dom/cjs/react-dom.production.js = 943.57 kB 940.45 kB = 211.30 kB 210.63 kB
facebook-www/ReactART-dev.modern.js = 1,023.68 kB 1,020.22 kB = 201.57 kB 200.97 kB
facebook-www/ReactART-dev.classic.js = 1,036.27 kB 1,032.63 kB = 203.99 kB 203.34 kB
facebook-www/ReactTestRenderer-dev.classic.js = 942.29 kB 938.87 kB = 188.00 kB 187.40 kB
facebook-www/ReactTestRenderer-dev.modern.js = 942.28 kB 938.87 kB = 188.00 kB 187.40 kB
oss-experimental/react-dom/cjs/react-dom-unstable_testing.development.js = 1,363.92 kB 1,358.86 kB = 301.41 kB 300.61 kB
oss-experimental/react-dom/umd/react-dom.development.js = 1,410.58 kB 1,405.30 kB = 300.11 kB 299.24 kB
oss-experimental/react-dom/cjs/react-dom.development.js = 1,345.87 kB 1,340.81 kB = 297.05 kB 296.25 kB
oss-stable/react-dom/umd/react-dom.development.js = 1,397.06 kB 1,391.78 kB = 297.67 kB 296.83 kB
oss-stable-semver/react-dom/umd/react-dom.development.js = 1,397.03 kB 1,391.76 kB = 297.65 kB 296.80 kB
oss-stable/react-dom/cjs/react-dom.development.js = 1,333.00 kB 1,327.94 kB = 294.65 kB 293.85 kB
oss-stable-semver/react-dom/cjs/react-dom.development.js = 1,332.98 kB 1,327.92 kB = 294.62 kB 293.82 kB
oss-experimental/react-art/umd/react-art.production.min.js = 138.25 kB 137.68 kB = 43.09 kB 42.93 kB
oss-stable/react-art/umd/react-art.production.min.js = 136.42 kB 135.84 kB = 42.51 kB 42.38 kB
oss-stable-semver/react-art/umd/react-art.production.min.js = 136.37 kB 135.79 kB = 42.48 kB 42.36 kB
oss-experimental/react-reconciler/cjs/react-reconciler.profiling.js = 732.98 kB 729.73 kB = 158.33 kB 157.77 kB
oss-stable/react-reconciler/cjs/react-reconciler.profiling.js = 725.56 kB 722.30 kB = 156.65 kB 156.11 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler.profiling.js = 725.53 kB 722.28 kB = 156.62 kB 156.08 kB
oss-experimental/react-reconciler/cjs/react-reconciler.production.js = 691.78 kB 688.66 kB = 150.97 kB 150.43 kB
oss-stable/react-reconciler/cjs/react-reconciler.production.js = 684.36 kB 681.24 kB = 149.32 kB 148.67 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler.production.js = 684.33 kB 681.21 kB = 149.29 kB 148.63 kB
oss-experimental/react-reconciler/cjs/react-reconciler.profiling.min.js = 125.51 kB 124.92 kB = 38.40 kB 38.25 kB
oss-stable/react-reconciler/cjs/react-reconciler.profiling.min.js = 123.64 kB 123.05 kB = 37.77 kB 37.58 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler.profiling.min.js = 123.61 kB 123.02 kB = 37.75 kB 37.56 kB
oss-experimental/react-test-renderer/cjs/react-test-renderer.production.js = 606.54 kB 603.56 kB = 135.74 kB 135.22 kB
oss-stable/react-test-renderer/cjs/react-test-renderer.production.js = 605.14 kB 602.15 kB = 135.42 kB 134.90 kB
oss-stable-semver/react-test-renderer/cjs/react-test-renderer.production.js = 605.11 kB 602.13 kB = 135.39 kB 134.87 kB
oss-experimental/react-art/cjs/react-art.production.js = 599.72 kB 596.74 kB = 134.07 kB 133.56 kB
oss-experimental/react-reconciler/cjs/react-reconciler.production.min.js = 116.46 kB 115.88 kB = 35.98 kB 35.81 kB
oss-stable/react-art/cjs/react-art.production.js = 592.43 kB 589.45 kB = 132.37 kB 131.85 kB
oss-stable-semver/react-art/cjs/react-art.production.js = 592.41 kB 589.43 kB = 132.34 kB 131.83 kB
oss-stable/react-reconciler/cjs/react-reconciler.production.min.js = 114.59 kB 114.01 kB = 35.38 kB 35.18 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler.production.min.js = 114.56 kB 113.98 kB = 35.36 kB 35.15 kB
oss-experimental/react-test-renderer/cjs/react-test-renderer.production.min.js = 108.60 kB 108.03 kB = 33.28 kB 33.14 kB
oss-experimental/react-test-renderer/umd/react-test-renderer.production.min.js = 108.91 kB 108.34 kB = 33.59 kB 33.44 kB
oss-stable/react-test-renderer/umd/react-test-renderer.production.min.js = 108.64 kB 108.07 kB = 33.55 kB 33.39 kB
oss-stable-semver/react-test-renderer/umd/react-test-renderer.production.min.js = 108.59 kB 108.02 kB = 33.53 kB 33.36 kB
oss-stable/react-test-renderer/cjs/react-test-renderer.production.min.js = 108.33 kB 107.76 kB = 33.22 kB 33.06 kB
oss-stable-semver/react-test-renderer/cjs/react-test-renderer.production.min.js = 108.28 kB 107.71 kB = 33.19 kB 33.03 kB
oss-experimental/react-art/umd/react-art.development.js = 967.25 kB 962.12 kB = 204.77 kB 203.99 kB
oss-experimental/react-reconciler/cjs/react-reconciler.development.js = 950.77 kB 945.71 kB = 204.23 kB 203.40 kB
oss-stable/react-art/umd/react-art.development.js = 957.16 kB 952.03 kB = 202.99 kB 202.20 kB
oss-stable-semver/react-art/umd/react-art.development.js = 957.14 kB 952.01 kB = 202.97 kB 202.17 kB
oss-stable/react-reconciler/cjs/react-reconciler.development.js = 941.05 kB 935.99 kB = 202.40 kB 201.56 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler.development.js = 941.02 kB 935.96 kB = 202.37 kB 201.53 kB
react-native/implementations/ReactNativeRenderer-profiling.js = 350.08 kB 348.17 kB = 61.61 kB 61.41 kB
oss-experimental/react-art/cjs/react-art.production.min.js = 101.02 kB 100.45 kB = 30.98 kB 30.82 kB
react-native/implementations/ReactFabric-profiling.js = 340.89 kB 338.98 kB = 59.86 kB 59.66 kB
facebook-react-native/react-test-renderer/cjs/ReactTestRenderer-profiling.js = 328.43 kB 326.58 kB = 57.72 kB 57.52 kB
oss-stable/react-art/cjs/react-art.production.min.js = 99.19 kB 98.62 kB = 30.45 kB 30.29 kB
oss-stable-semver/react-art/cjs/react-art.production.min.js = 99.14 kB 98.57 kB = 30.42 kB 30.26 kB
oss-experimental/react-test-renderer/umd/react-test-renderer.development.js = 862.43 kB 857.46 kB = 182.41 kB 181.61 kB
oss-stable/react-test-renderer/umd/react-test-renderer.development.js = 861.13 kB 856.16 kB = 182.17 kB 181.36 kB
oss-stable-semver/react-test-renderer/umd/react-test-renderer.development.js = 861.11 kB 856.13 kB = 182.14 kB 181.33 kB
oss-experimental/react-art/cjs/react-art.development.js = 850.43 kB 845.51 kB = 185.72 kB 184.91 kB
react-native/implementations/ReactNativeRenderer-prod.js = 330.66 kB 328.75 kB = 58.46 kB 58.22 kB
oss-experimental/react-test-renderer/cjs/react-test-renderer.development.js = 823.66 kB 818.88 kB = 180.56 kB 179.70 kB
oss-stable/react-test-renderer/cjs/react-test-renderer.development.js = 822.40 kB 817.62 kB = 180.30 kB 179.44 kB
oss-stable-semver/react-test-renderer/cjs/react-test-renderer.development.js = 822.38 kB 817.60 kB = 180.26 kB 179.41 kB
react-native/implementations/ReactNativeRenderer-profiling.fb.js = 364.93 kB 362.81 kB = 64.17 kB 63.89 kB
react-native/implementations/ReactNativeRenderer-dev.js = 988.11 kB 982.34 kB = 200.30 kB 199.36 kB
oss-stable/react-art/cjs/react-art.development.js = 840.84 kB 835.92 kB = 183.90 kB 183.10 kB
oss-stable-semver/react-art/cjs/react-art.development.js = 840.82 kB 835.90 kB = 183.87 kB 183.07 kB
react-native/implementations/ReactFabric-dev.js = 971.82 kB 966.05 kB = 196.05 kB 195.13 kB
react-native/implementations/ReactFabric-profiling.fb.js = 357.40 kB 355.27 kB = 62.71 kB 62.44 kB
facebook-react-native/react-test-renderer/cjs/ReactTestRenderer-prod.js = 312.54 kB 310.69 kB = 55.28 kB 55.07 kB
react-native/implementations/ReactNativeRenderer-dev.fb.js = 1,018.91 kB 1,012.84 kB = 205.28 kB 204.38 kB
react-native/implementations/ReactFabric-prod.js = 321.50 kB 319.58 kB = 56.73 kB 56.49 kB
react-native/implementations/ReactFabric-dev.fb.js = 1,004.30 kB 998.24 kB = 201.41 kB 200.51 kB
react-native/implementations/ReactNativeRenderer-prod.fb.js = 337.61 kB 335.57 kB = 59.95 kB 59.70 kB
react-native/implementations/ReactFabric-prod.fb.js = 330.13 kB 328.09 kB = 58.53 kB 58.29 kB
facebook-react-native/react-test-renderer/cjs/ReactTestRenderer-dev.js = 930.06 kB 924.30 kB = 186.03 kB 185.16 kB
oss-experimental/react-reconciler/cjs/react-reconciler-reflection.development.js = 18.55 kB 18.43 kB = 5.33 kB 5.29 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler-reflection.development.js = 18.31 kB 18.20 kB = 5.27 kB 5.23 kB
oss-stable/react-reconciler/cjs/react-reconciler-reflection.development.js = 18.31 kB 18.20 kB = 5.27 kB 5.23 kB

Generated by 🚫 dangerJS against 6518505

@gnoff gnoff force-pushed the committed-hoistables branch 3 times, most recently from 27aa27a to d14d9d6 Compare November 27, 2023 22:24
…s at this point. Supporting this pattern required React to have a concept of an indeterminate component so that when a component first renders it can turn into either a ClassComponent or a FunctionComponent depending on what it returns. While this feature was deprecated and put behind a flag it is still in stable. This change remvoes the flag, removes the warnings, and removes the concept of IndeterminateComponent from the React codebase.
Hoistable elements and resources in fallbacks should not flush unless the fallback itself flushes.

Previously we used a renderState-local binding to track the resources for the currently rendering boundary. Instead we now track this in the task itself and pass it to the functions that depend on it. This cleans up an unfortunate factoring that I put in before where during flushing we had to mimic the currently rendering Boundary to hoist correctly. This new factoring does the same thing but in a much clearer way.

I do track the Boundary state separately from the Boundary itself on the task as a hot path optimization to avoid having to existence check the boundary in `pushStartInstance`. Conceptually tracking the boundary itself is sufficient but this eliminates an extra condition check.

The implementation ended up not merging the boundary resource concept with hoistable state due to the very different nature in which these things need to hoist (one during task completion and the other during flush but only when flushing late boundaries). Given that I've gone back to resource specific naming rather than calling it BoundaryState.
@@ -3658,11 +3770,12 @@ function flushSegment(
request: Request,
destination: Destination,
segment: Segment,
rootBoundary: null | SuspenseBoundary,
Copy link
Collaborator

Choose a reason for hiding this comment

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

This feels leaky given that these can flush independently of any boundary. At least we should probably name this something much more esoteric and specific because this really means that the whole flushing mechanism is coupled to a very specific flushing strategy - which I'm not sure we will remember when we build SuspenseList etc. which will break some assumptions.

@@ -284,6 +293,11 @@ type Segment = {
textEmbedded: boolean,
};

type Hoistables = {
state: HoistableState,
fallbacks: Set<Hoistables>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does this really need to be a set? Wouldn't you know if it's added already?

// Next we merge the boundary Hoistables into the task Hoistables. In the process the boundary assumes
// the task Hoistables internal state so later if a child task also completes it will merge with
// the appropriate sets
mergeHoistables.call(parentHoistables, hoistables);
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a common call. Shouldn't use .call deopt. Better to split it out into a separate helper function.

target: HoistableState,
source: HoistableState,
) {
target.charset.push(...source.charset);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's not use spread since it'll get transpiled to a form that we don't know and likely worse than the alternative we'd do manually.

blockedSegment: Segment, // the segment we'll write to
blockedHoistables: Hoistables, // the hoistables we'll write to
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why isn't this just blockedBoundary.hoistables?

function finishedTask(
request: Request,
boundary: Root | SuspenseBoundary,
segment: null | Segment,
hoistables: Hoistables,
parentHoistables: null | Hoistables,
Copy link
Collaborator

Choose a reason for hiding this comment

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

The parentHoistables is really reasoning on a distance here that I'm not really comfortable reasoning about. Especially in the resuming path where the nearest boundary isn't necessarily even reified. A resumed boundary is just skipped.

@gnoff
Copy link
Collaborator Author

gnoff commented Jan 24, 2024

superceded by: #28069

@gnoff gnoff deleted the committed-hoistables branch January 24, 2024 06:19
gnoff added a commit that referenced this pull request Jan 30, 2024
…uspense Boundaries (#28069)

Updates Fizz to handle Hoistables (Resources and Elements) in a way that
better aligns with Suspense fallbacks

1. Hoistable Elements inside a fallback (regardless of how deep and how
many additional boundaries are intermediate) will be ignored. The
reasoning is fallbacks are transient and since there is not good way to
clean up hoistables because they escape their Suspense container its
better to not emit them in the first place. SSR fallbacks are already
not full fidelity because they never hydrate so this aligns with that
somewhat.
2. Hoistable stylesheets in fallbacks will only block the reveal of a
parent suspense boundary if the fallback is going to flush with that
completed parent suspense boundary. Previously if you rendered a
stylesheet Resource inside a fallback any parent suspense boundaries
that completed after the shell flushed would include that resource in
the set required to resolve before the boundary reveal happens on the
client. This is not a semantic change, just a performance optimization
3. preconnect and preload hoistable queues are gone, if you want to
optimize resource loading you shoudl use `ReactDOM.preconnect` and
`ReactDOM.preload`. `viewport` meta tags get their own queue because
they need to go before any preloads since they affect the media state.

In addition to those functional changes this PR also refactors the
boundary resource tracking by moving it to the task rather than using
function calls at the start of each render and flush. Tasks also now
track whether they are a fallback task

supercedes prior work here: #27534
github-actions bot pushed a commit that referenced this pull request Jan 30, 2024
…uspense Boundaries (#28069)

Updates Fizz to handle Hoistables (Resources and Elements) in a way that
better aligns with Suspense fallbacks

1. Hoistable Elements inside a fallback (regardless of how deep and how
many additional boundaries are intermediate) will be ignored. The
reasoning is fallbacks are transient and since there is not good way to
clean up hoistables because they escape their Suspense container its
better to not emit them in the first place. SSR fallbacks are already
not full fidelity because they never hydrate so this aligns with that
somewhat.
2. Hoistable stylesheets in fallbacks will only block the reveal of a
parent suspense boundary if the fallback is going to flush with that
completed parent suspense boundary. Previously if you rendered a
stylesheet Resource inside a fallback any parent suspense boundaries
that completed after the shell flushed would include that resource in
the set required to resolve before the boundary reveal happens on the
client. This is not a semantic change, just a performance optimization
3. preconnect and preload hoistable queues are gone, if you want to
optimize resource loading you shoudl use `ReactDOM.preconnect` and
`ReactDOM.preload`. `viewport` meta tags get their own queue because
they need to go before any preloads since they affect the media state.

In addition to those functional changes this PR also refactors the
boundary resource tracking by moving it to the task rather than using
function calls at the start of each render and flush. Tasks also now
track whether they are a fallback task

supercedes prior work here: #27534

DiffTrain build for [554fc49](554fc49)
gaearon pushed a commit that referenced this pull request Feb 3, 2024
…uspense Boundaries (#28069)

Updates Fizz to handle Hoistables (Resources and Elements) in a way that
better aligns with Suspense fallbacks

1. Hoistable Elements inside a fallback (regardless of how deep and how
many additional boundaries are intermediate) will be ignored. The
reasoning is fallbacks are transient and since there is not good way to
clean up hoistables because they escape their Suspense container its
better to not emit them in the first place. SSR fallbacks are already
not full fidelity because they never hydrate so this aligns with that
somewhat.
2. Hoistable stylesheets in fallbacks will only block the reveal of a
parent suspense boundary if the fallback is going to flush with that
completed parent suspense boundary. Previously if you rendered a
stylesheet Resource inside a fallback any parent suspense boundaries
that completed after the shell flushed would include that resource in
the set required to resolve before the boundary reveal happens on the
client. This is not a semantic change, just a performance optimization
3. preconnect and preload hoistable queues are gone, if you want to
optimize resource loading you shoudl use `ReactDOM.preconnect` and
`ReactDOM.preload`. `viewport` meta tags get their own queue because
they need to go before any preloads since they affect the media state.

In addition to those functional changes this PR also refactors the
boundary resource tracking by moving it to the task rather than using
function calls at the start of each render and flush. Tasks also now
track whether they are a fallback task

supercedes prior work here: #27534
EdisonVan pushed a commit to EdisonVan/react that referenced this pull request Apr 15, 2024
…uspense Boundaries (facebook#28069)

Updates Fizz to handle Hoistables (Resources and Elements) in a way that
better aligns with Suspense fallbacks

1. Hoistable Elements inside a fallback (regardless of how deep and how
many additional boundaries are intermediate) will be ignored. The
reasoning is fallbacks are transient and since there is not good way to
clean up hoistables because they escape their Suspense container its
better to not emit them in the first place. SSR fallbacks are already
not full fidelity because they never hydrate so this aligns with that
somewhat.
2. Hoistable stylesheets in fallbacks will only block the reveal of a
parent suspense boundary if the fallback is going to flush with that
completed parent suspense boundary. Previously if you rendered a
stylesheet Resource inside a fallback any parent suspense boundaries
that completed after the shell flushed would include that resource in
the set required to resolve before the boundary reveal happens on the
client. This is not a semantic change, just a performance optimization
3. preconnect and preload hoistable queues are gone, if you want to
optimize resource loading you shoudl use `ReactDOM.preconnect` and
`ReactDOM.preload`. `viewport` meta tags get their own queue because
they need to go before any preloads since they affect the media state.

In addition to those functional changes this PR also refactors the
boundary resource tracking by moving it to the task rather than using
function calls at the start of each render and flush. Tasks also now
track whether they are a fallback task

supercedes prior work here: facebook#27534
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.

4 participants