Skip to content

[Fizz] Don't handle errors in completeBoundary instruction #33073

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

Merged
merged 3 commits into from
May 1, 2025

Conversation

sebmarkbage
Copy link
Collaborator

Stacked on #33066 and #33068.

Currently we're passing errorDigest to completeBoundary if there is a client side error (only CSS loading atm). This only exists because of completeBoundaryWithStyles. Normally if there's a server-side error we'd emit the clientRenderBoundary instruction instead. This adds unnecessary code to the common case where all styles are in the head. This is about to get worse with batching because client render shouldn't be throttled but complete should be.

The first commit moves the client render logic inline into completeBoundaryWithStyles so we only pay for it when styles are used.

However, the approach I went with in the second commit is to reuse the $RX instruction instead (clientRenderBoundary). That way if you have both it ends up being amortized. However, it does mean we have to emit the $RX (along with the $RC helper if any completeBoundaryWithStyles instruction is needed.

@sebmarkbage sebmarkbage requested a review from gnoff April 30, 2025 20:28
@github-actions github-actions bot added the React Core Team Opened by a member of the React Core Team label Apr 30, 2025
@react-sizebot
Copy link

react-sizebot commented Apr 30, 2025

Comparing: bb57fa7...83fd34b

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 = 1.83 kB 1.83 kB
oss-stable/react-dom/cjs/react-dom-client.production.js = 527.81 kB 527.81 kB = 93.08 kB 93.08 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 = 633.44 kB 633.44 kB = 111.27 kB 111.27 kB
facebook-www/ReactDOM-prod.classic.js = 671.22 kB 671.22 kB = 117.71 kB 117.71 kB
facebook-www/ReactDOM-prod.modern.js = 661.50 kB 661.50 kB = 116.15 kB 116.15 kB
oss-experimental/react-dom/unstable_server-external-runtime.js = 8.82 kB 8.50 kB = 2.28 kB 2.26 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name +/- Base Current +/- gzip Base gzip Current gzip
oss-experimental/react-dom/cjs/react-dom-server.edge.development.js = 419.90 kB 419.06 kB = 73.00 kB 72.99 kB
oss-experimental/react-dom/cjs/react-dom-server.browser.development.js = 418.89 kB 418.05 kB = 72.78 kB 72.78 kB
oss-experimental/react-dom/cjs/react-dom-server.node.development.js = 414.90 kB 414.06 kB = 72.18 kB 72.18 kB
oss-stable/react-dom/cjs/react-dom-server.edge.development.js = 383.71 kB 382.92 kB = 68.93 kB 68.92 kB
oss-stable-semver/react-dom/cjs/react-dom-server.edge.development.js = 383.64 kB 382.85 kB = 68.88 kB 68.87 kB
facebook-www/ReactDOMServerStreaming-dev.modern.js = 369.93 kB 369.17 kB +0.16% 66.50 kB 66.61 kB
oss-stable/react-dom/cjs/react-dom-server.browser.development.js = 382.93 kB 382.14 kB = 68.78 kB 68.77 kB
oss-stable-semver/react-dom/cjs/react-dom-server.browser.development.js = 382.85 kB 382.07 kB = 68.73 kB 68.72 kB
oss-stable/react-dom/cjs/react-dom-server.node.development.js = 379.47 kB 378.68 kB = 68.16 kB 68.15 kB
oss-stable-semver/react-dom/cjs/react-dom-server.node.development.js = 379.39 kB 378.61 kB = 68.10 kB 68.10 kB
oss-experimental/react-dom/cjs/react-dom-server-legacy.browser.development.js = 392.55 kB 391.73 kB = 69.60 kB 69.60 kB
oss-experimental/react-dom/cjs/react-dom-server-legacy.node.development.js = 392.55 kB 391.72 kB = 69.60 kB 69.60 kB
oss-experimental/react-markup/cjs/react-markup.development.js = 362.52 kB 361.76 kB +0.17% 65.06 kB 65.17 kB
facebook-www/ReactDOMServer-dev.classic.js = 382.08 kB 381.26 kB = 68.39 kB 68.38 kB
facebook-www/ReactDOMServer-dev.modern.js = 378.63 kB 377.80 kB = 67.86 kB 67.85 kB
oss-stable/react-dom/cjs/react-dom-server-legacy.browser.development.js = 365.88 kB 365.05 kB = 66.37 kB 66.35 kB
oss-stable/react-dom/cjs/react-dom-server-legacy.node.development.js = 365.88 kB 365.05 kB = 66.37 kB 66.35 kB
oss-stable-semver/react-dom/cjs/react-dom-server-legacy.browser.development.js = 365.85 kB 365.02 kB = 66.35 kB 66.33 kB
oss-stable-semver/react-dom/cjs/react-dom-server-legacy.node.development.js = 365.85 kB 365.02 kB = 66.35 kB 66.33 kB
oss-experimental/react-dom/cjs/react-dom-server.bun.development.js = 351.30 kB 350.47 kB = 66.72 kB 66.70 kB
oss-stable/react-dom/cjs/react-dom-server.bun.development.js = 326.59 kB 325.76 kB = 63.43 kB 63.40 kB
oss-stable-semver/react-dom/cjs/react-dom-server.bun.development.js = 326.51 kB 325.68 kB = 63.40 kB 63.38 kB
oss-experimental/react-markup/cjs/react-markup.react-server.production.js = 321.06 kB 320.23 kB = 59.85 kB 59.82 kB
oss-experimental/react-dom/cjs/react-dom-server.edge.production.js = 267.63 kB 266.87 kB = 47.42 kB 47.38 kB
oss-experimental/react-dom/cjs/react-dom-server.node.production.js = 263.64 kB 262.87 kB = 46.43 kB 46.43 kB
oss-experimental/react-dom/cjs/react-dom-server.browser.production.js = 261.69 kB 260.92 kB = 45.28 kB 45.26 kB
oss-stable/react-dom/cjs/react-dom-server.edge.production.js = 239.33 kB 238.55 kB = 43.84 kB 43.79 kB
oss-stable-semver/react-dom/cjs/react-dom-server.edge.production.js = 239.25 kB 238.48 kB = 43.81 kB 43.76 kB
oss-stable/react-dom/cjs/react-dom-server.node.production.js = 235.97 kB 235.20 kB = 42.86 kB 42.84 kB
oss-stable-semver/react-dom/cjs/react-dom-server.node.production.js = 235.90 kB 235.12 kB = 42.84 kB 42.81 kB
oss-stable/react-dom/cjs/react-dom-server.browser.production.js = 234.13 kB 233.35 kB = 41.90 kB 41.85 kB
oss-stable-semver/react-dom/cjs/react-dom-server.browser.production.js = 234.05 kB 233.27 kB = 41.87 kB 41.83 kB
oss-experimental/react-dom/cjs/react-dom-server.bun.production.js = 239.77 kB 238.96 kB = 43.04 kB 43.01 kB
oss-experimental/react-dom/cjs/react-dom-server-legacy.node.production.js = 238.47 kB 237.64 kB = 43.51 kB 43.48 kB
oss-experimental/react-dom/cjs/react-dom-server-legacy.browser.production.js = 233.39 kB 232.56 kB = 41.61 kB 41.58 kB
facebook-www/ReactDOMServerStreaming-prod.modern.js = 226.88 kB 226.07 kB = 41.63 kB 41.58 kB
facebook-www/ReactDOMServer-prod.classic.js = 225.30 kB 224.47 kB = 40.38 kB 40.35 kB
facebook-www/ReactDOMServer-prod.modern.js = 222.62 kB 221.79 kB = 40.05 kB 40.02 kB
oss-experimental/react-markup/cjs/react-markup.production.js = 220.32 kB 219.49 kB = 40.58 kB 40.55 kB
oss-stable/react-dom/cjs/react-dom-server.bun.production.js = 219.39 kB 218.55 kB = 40.28 kB 40.26 kB
oss-stable-semver/react-dom/cjs/react-dom-server.bun.production.js = 219.31 kB 218.48 kB = 40.26 kB 40.23 kB
oss-stable/react-dom/cjs/react-dom-server-legacy.node.production.js = 218.93 kB 218.08 kB = 40.73 kB 40.70 kB
oss-stable-semver/react-dom/cjs/react-dom-server-legacy.node.production.js = 218.91 kB 218.06 kB = 40.71 kB 40.68 kB
oss-stable/react-dom/cjs/react-dom-server-legacy.browser.production.js = 214.42 kB 213.57 kB = 38.98 kB 38.94 kB
oss-stable-semver/react-dom/cjs/react-dom-server-legacy.browser.production.js = 214.39 kB 213.54 kB = 38.96 kB 38.92 kB
oss-experimental/react-dom/unstable_server-external-runtime.js = 8.82 kB 8.50 kB = 2.28 kB 2.26 kB

Generated by 🚫 dangerJS against 83fd34b

This means we need to always include it with the complete boundary with styles function.
@sebmarkbage sebmarkbage force-pushed the fizzcompleteerror branch from 9f53f9d to 83fd34b Compare May 1, 2025 18:25
@sebmarkbage sebmarkbage merged commit ee077b6 into facebook:main May 1, 2025
239 checks passed
github-actions bot pushed a commit that referenced this pull request May 1, 2025
Stacked on #33066 and #33068.

Currently we're passing `errorDigest` to `completeBoundary` if there is
a client side error (only CSS loading atm). This only exists because of
`completeBoundaryWithStyles`. Normally if there's a server-side error
we'd emit the `clientRenderBoundary` instruction instead. This adds
unnecessary code to the common case where all styles are in the head.
This is about to get worse with batching because client render shouldn't
be throttled but complete should be.

The first commit moves the client render logic inline into
`completeBoundaryWithStyles` so we only pay for it when styles are used.

However, the approach I went with in the second commit is to reuse the
`$RX` instruction instead (`clientRenderBoundary`). That way if you have
both it ends up being amortized. However, it does mean we have to emit
the `$RX` (along with the `$RC` helper if any
`completeBoundaryWithStyles` instruction is needed.

DiffTrain build for [ee077b6](ee077b6)
sebmarkbage added a commit that referenced this pull request May 1, 2025
Stacked on #33073.

React semantics is that Suspense boundaries reveal with a throttle
(300ms). That helps avoid flashing reveals when a stream reveals many
individual steps back to back. It can also improve overall performance
by batching the layout and paint work that has to happen at each step.

Unfortunately we never implemented this for SSR streaming - only for
client navigations. This is highly noticeable on very dynamic sites with
lots of Suspense boundaries. It can look good with a client nav but feel
glitchy when you reload the page or initial load.

This fixes the Fizz runtime to be throttled and reveals batched into a
single paint at a time. We do this by first tracking the last paint
after the complete (this will be the first paint if `rel="expect"` is
respected). Then in the `completeBoundary` operation we queue the
operation and then flush it all into a throttled batch.

Another motivation is that View Transitions need to operate as a batch
and individual steps get queued in a sequence so it's extra important to
include as much content as possible in each animated step. This will be
done in a follow up for SSR View Transitions.
github-actions bot pushed a commit that referenced this pull request May 1, 2025
Stacked on #33073.

React semantics is that Suspense boundaries reveal with a throttle
(300ms). That helps avoid flashing reveals when a stream reveals many
individual steps back to back. It can also improve overall performance
by batching the layout and paint work that has to happen at each step.

Unfortunately we never implemented this for SSR streaming - only for
client navigations. This is highly noticeable on very dynamic sites with
lots of Suspense boundaries. It can look good with a client nav but feel
glitchy when you reload the page or initial load.

This fixes the Fizz runtime to be throttled and reveals batched into a
single paint at a time. We do this by first tracking the last paint
after the complete (this will be the first paint if `rel="expect"` is
respected). Then in the `completeBoundary` operation we queue the
operation and then flush it all into a throttled batch.

Another motivation is that View Transitions need to operate as a batch
and individual steps get queued in a sequence so it's extra important to
include as much content as possible in each animated step. This will be
done in a follow up for SSR View Transitions.

DiffTrain build for [ee7fee8](ee7fee8)
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