Skip to content

[turbopack] Reduce native React Compiler work - #96820

Merged
lukesandberg merged 4 commits into
canaryfrom
codex/turbopack-rust-react-compiler-scope
Aug 10, 2026
Merged

[turbopack] Reduce native React Compiler work#96820
lukesandberg merged 4 commits into
canaryfrom
codex/turbopack-rust-react-compiler-scope

Conversation

@marcoshernanz

@marcoshernanz marcoshernanz commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

What?

  • Use the released swc_ecma_react_compiler::fast_check::is_required API to skip React Compiler work for modules that cannot change in native infer mode.
  • Keep explicit annotation and all modes unconditional.
  • Delete Next.js's duplicate React Compiler predicates and use the same upstream check from the native N-API binding.
  • Fail open from the N-API check on unreadable files, fatal parse failures, and recovered parser errors.
  • Keep the client-runtime-only compiler out of App SSR, matching the existing Babel integration.
  • Move the workspace to the coherent SWC 76 dependency family, including the official mdxjs-rs-turbopack branch, with no duplicate SWC 75 stack.
  • Keep the React Compiler dependency/module native-only; the WASM facade already deliberately fails open.

This consumes the implementation landed in swc-project/swc#12105, released in swc_ecma_react_compiler 23.0.0. Its contract is conservative: false positives add compiler work, while a negative result guarantees that compilation cannot alter the program.

Why?

The native compiler currently runs for every parsed module in infer mode and is configured for both browser and App SSR contexts. This adds avoidable AST conversion/compiler work and compiles hydrated client modules in a server context that the existing Turbopack Babel path excludes.

This matters for large applications such as v0. Their legacy Babel React Compiler path creates a separate machine-sized Node worker pool in addition to PostCSS. Moving to the native path removes that pool; this patch makes the native path cheaper while preserving the established browser-only scope.

Performance

Upstream fast check on the v0 corpus

The final SWC predicate was checked against 1,816 real v0 modules (10.46 MB):

  • selected 302 modules
  • retained all 257 modules whose output actually changed
  • zero false negatives
  • scanned the full corpus in 20.624 ms
  • reduced the measured full compiler pipeline from 2,371.956 ms to 1,906.180 ms: -19.64%

This Next.js patch only

Real v0 homepage, cold .next, Chromium interaction gate, 16 vCPU / 32 GB, exact Next canary 7916855653, exact v0 commit 1ab042a47c, three samples per arm. Both arms use the native compiler.

Median Unpatched native This PR Change
Visible interactive UI 50.737 s 48.574 s -4.26%
Network quiet 70.125 s 67.546 s -3.68%
Aggregate CPU 450 s 418 s -7.11%
Peak process-tree RSS 7,904,772 KB 7,823,008 KB -1.03%

All three paired visible, quiet, and CPU deltas favored the patch. The RSS difference is inside noise, so this PR makes no patch-only memory claim.

v0 legacy Babel path to native + this PR

Both arms use TURBO_ENGINE_EVICT_AFTER_SNAPSHOT=1 and remain open for 120 seconds after network quiet.

Median Legacy Babel Native + this PR Change
Visible interactive UI 52.411 s 48.372 s -7.71%
Peak process-tree RSS 12.19 GiB 7.39 GiB -39.40%
RSS at +120 s 5.31 GiB 3.02 GiB -43.07%
Aggregate CPU 480 s 429 s -10.63%
Processes at +120 s 16 4 -75.00%

The large memory/process delta comes from switching v0 off the external Babel pool, not from this source diff alone. v0 still needs to enable the native compiler configuration separately.

Every accepted browser run required HTTP 200, a visible nonblank UI with at least ten controls, zero Next overlays/page errors, and a verified prompt interaction. The complete Next process session was sampled every 100 ms.

Validation

  • cargo fmt --all -- --check
  • affected Rust cargo check
  • affected Clippy with warnings denied, including Turbopack tests
  • React Compiler unit tests: 2 passed
  • React Compiler integration tests: 3 passed
  • Turbopack snapshots: 114 passed
  • direct native N-API/Node smoke: wrapped JSX and member hooks select; plain modules skip; recovered parse errors and missing files fail open
  • dependency trees: native includes swc_ecma_react_compiler; WASI excludes it; no swc_core 75 remains
  • official mdxjs-rs-turbopack SWC 76 bump: 188 tests passed
  • final GPT-5.6 Sol + Claude Opus 5 xhigh autoreview: clean, 0.98 confidence from both reviewers
  • real-v0 cold browser matrix, 120-second memory soak, and full production build: 44 Workflow steps / 10 workflows, 2,722/2,722 prerenders

Co-Authored-By: Marcos Hernanz <96699542+marcoshernanz@users.noreply.github.com>
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Tests Passed

Commit: 01a3e98

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Stats from current PR

✅ No significant changes detected

📊 All Metrics
📖 Metrics Glossary

Dev Server Metrics:

  • Listen = TCP port starts accepting connections
  • First Request = HTTP server returns successful response
  • Cold = Fresh build (no cache)
  • Warm = With cached build artifacts

Build Metrics:

  • Fresh = Clean build (no .next directory)
  • Cached = With existing .next directory

Change Thresholds:

  • Time: Changes < 50ms AND < 10%, OR < 2% are insignificant
  • Size: Changes < 1KB AND < 1% are insignificant
  • All other changes are flagged to catch regressions

⚡ Dev Server

Metric Canary PR Change Trend
Cold (Listen) 811ms 811ms ▁▁▁▁█
Cold (Ready in log) 779ms 782ms ▂▁▁▁█
Cold (First Request) 1.262s 1.263s ▃▂▂▁█
Warm (Listen) 811ms 812ms ▂▂▂▂█
Warm (Ready in log) 783ms 782ms ▂▁▂▁█
Warm (First Request) 1.269s 1.258s ▃▂▂▁█
📦 Dev Server (Webpack) (Legacy)

📦 Dev Server (Webpack)

Metric Canary PR Change Trend
Cold (Listen) 814ms 813ms █████
Cold (Ready in log) 789ms 789ms ▅▆█▃▆
Cold (First Request) 3.355s 3.371s ▅▅█▃█
Warm (Listen) 814ms 813ms █▅▇▁▇
Warm (Ready in log) 791ms 789ms ▇▇█▁█
Warm (First Request) 3.378s 3.478s ▆▅█▁█

⚡ Production Builds

Metric Canary PR Change Trend
Fresh Build 5.626s 5.594s ▄▃▂▁█
Cached Build 2.869s 2.897s ▄▃▂▁█
📦 Production Builds (Webpack) (Legacy)

📦 Production Builds (Webpack)

Metric Canary PR Change Trend
Fresh Build 24.919s 24.937s ▄▆▂▁█
Cached Build 25.054s 25.246s ▅▇▇▂█
node_modules Size 553 MB 553 MB ▁▁▁▁▁
📦 Bundle Sizes

Bundle Sizes

⚡ Turbopack

Client

Main Bundles
Canary PR Change
050icza-xjz0i.js gzip 5.73 kB N/A -
075w8k05wqbxg.js gzip 152 B N/A -
07jdby0ue616s.js gzip 450 B N/A -
0bjdc8muo74n5.js gzip 8.71 kB N/A -
0cz1d0mv5g_q7.js gzip 39.4 kB 39.4 kB
0fz75kvm47217.js gzip 157 B N/A -
0g5h9bc2rxz0h.js gzip 71.5 kB N/A -
0rci1f3or1a19.js gzip 13.3 kB N/A -
0v2vdqju5d3us.js gzip 65.6 kB N/A -
0wymx6umcmr-e.js gzip 156 B N/A -
1_2x714--ii1i.js gzip 8.76 kB N/A -
1-3y752pkth5-.js gzip 10 kB N/A -
194z3nzvcclm4.js gzip 158 B N/A -
1b2kxnxiyh5td.js gzip 156 B N/A -
1elt1qium-r2m.css gzip 115 B 115 B
1hy0e5cihni_x.js gzip 7.54 kB N/A -
1k6dd7su4cfei.js gzip 3.57 kB N/A -
1p_-361sg-xor.js gzip 156 B N/A -
1p-3_vnu3i9w8.js gzip 156 B N/A -
1tf1phijqlx9j.js gzip 220 B 220 B
1uzabyd1120a1.js gzip 8.71 kB N/A -
2-ufv8lc-g7gg.js gzip 10.6 kB N/A -
21kmjy_10x14f.js gzip 8.81 kB N/A -
28dhc6t85q1_p.js gzip 8.78 kB N/A -
2d-9gbr1pinw0.js gzip 156 B N/A -
2f-ilvczue-tp.js gzip 9.46 kB N/A -
2f1u17u5c8iny.js gzip 8.79 kB N/A -
2ikltg_8iegxw.js gzip 10.3 kB N/A -
2iupp4nrd6c1_.js gzip 156 B N/A -
2j0hi-p1x_5-f.js gzip 46.7 kB N/A -
2roru2mb_p8yo.js gzip 168 B N/A -
2vxi673cz1-t4.js gzip 8.79 kB N/A -
3_5ebngsihghe.js gzip 159 B N/A -
38-q43pzktqhs.js gzip 1.46 kB N/A -
3e42tdpo_93le.js gzip 161 B N/A -
3mrwxzed0ylgv.js gzip 13.1 kB N/A -
3nbojhxiy1qv_.js gzip 13.7 kB N/A -
3pchr-7emrys3.js gzip 163 B N/A -
41u5s3oe2-erp.js gzip 2.29 kB N/A -
445s_9hf8o7ao.js gzip 8.76 kB N/A -
turbopack-1l..-5yv.js gzip 3.73 kB 3.73 kB
0-6bcj16ji2wf.js gzip N/A 10.6 kB -
05bc8af8ar0hm.js gzip N/A 157 B -
07ryk0jced-sc.js gzip N/A 8.78 kB -
0ehfrsq4t9oxv.js gzip N/A 157 B -
0fcqiazz8rrj6.js gzip N/A 169 B -
0fyxlx-_ssw2o.js gzip N/A 46.7 kB -
0jwho9fkrb_t3.js gzip N/A 2.29 kB -
0omsbw8v56c76.js gzip N/A 71.5 kB -
0roh390ijzxa5.js gzip N/A 8.75 kB -
0ryyb26nk8l4-.js gzip N/A 65.6 kB -
0vex9w55ursqj.js gzip N/A 8.79 kB -
17oe55cu76cd7.js gzip N/A 450 B -
1drww5xikb-c-.js gzip N/A 9.46 kB -
1f0sbbzbtb8-d.js gzip N/A 156 B -
1g60xde_dv17t.js gzip N/A 8.79 kB -
1hfawbaxawa1b.js gzip N/A 156 B -
1uzv47btzam64.js gzip N/A 5.73 kB -
1vy7n7wxv_rh5.js gzip N/A 8.81 kB -
2-0i7pl900-ou.js gzip N/A 8.71 kB -
2-kcbngm7ik7y.js gzip N/A 8.75 kB -
24xppfz7hzt_u.js gzip N/A 161 B -
29p5-xa4jmdhg.js gzip N/A 13.7 kB -
2kgg_yiaz8rd6.js gzip N/A 155 B -
2lpk5_hknut8q.js gzip N/A 13.1 kB -
2o4cibp3awtbw.js gzip N/A 3.56 kB -
2ugc69z0t0ypz.js gzip N/A 1.46 kB -
2ysmo6k0h552j.js gzip N/A 156 B -
31v10264sxw__.js gzip N/A 150 B -
36dn8i-_3dnq5.js gzip N/A 10 kB -
37nj9nluvb6lr.js gzip N/A 157 B -
3a9sn6l54cidw.js gzip N/A 156 B -
3be3-77wi4dm2.js gzip N/A 156 B -
3fljpmwcjxqhx.js gzip N/A 10.3 kB -
3g7d_qk0nyha6.js gzip N/A 158 B -
3gz44skqdlsrb.js gzip N/A 8.71 kB -
3oslhuq9luvp2.js gzip N/A 7.55 kB -
3y9tus7kb5su0.js gzip N/A 13.3 kB -
Total 401 kB 401 kB ⚠️ +6 B

Server

Middleware
Canary PR Change
middleware-b..fest.js gzip 1.06 kB 1.06 kB
Total 1.06 kB 1.06 kB ✅ -1 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 875 B 876 B
Total 875 B 876 B ⚠️ +1 B
Build Cache
Canary PR Change
00000001.sst gzip 14.4 MB 14.8 MB 🔴 +373 kB (+3%)
00000002.sst gzip 14 MB 12.4 MB 🟢 1.59 MB (-11%)
00000003.sst gzip 13.6 MB 13.1 MB 🟢 547 kB (-4%)
00000004.sst gzip 13.1 MB 14.8 MB 🔴 +1.77 MB (+14%)
00000005.sst gzip 2.81 MB 2.81 MB
00000006.sst gzip 10.2 MB 10.2 MB
00000007.sst gzip 59 B 59 B
00000008.meta gzip 89 B 89 B
00000009.meta gzip 298 kB 298 kB
00000010.meta gzip 298 kB 298 kB
00000011.meta gzip 298 kB 298 kB
00000012.sst gzip 51.5 kB 52.6 kB 🔴 +1.06 kB (+2%)
00000013.sst gzip 1.85 MB 1.81 MB 🟢 41.5 kB (-2%)
00000014.sst gzip 59 B 59 B
00000015.meta gzip 116 B 116 B
00000016.meta gzip 325 kB 325 kB
00000017.meta gzip 405 kB 404 kB
00000018.sst gzip 52.4 kB 53.3 kB 🔴 +966 B (+2%)
00000019.sst gzip 1.38 MB 1.4 MB 🔴 +13.1 kB (+1%)
00000020.sst gzip 59 B 59 B
00000021.meta gzip 116 B 116 B
00000022.meta gzip 325 kB 325 kB
00000023.meta gzip 371 kB 371 kB
00000024.sst gzip 52.3 kB 53.4 kB 🔴 +1.14 kB (+2%)
00000025.sst gzip 1.38 MB 1.4 MB 🔴 +14.6 kB (+1%)
00000026.sst gzip 59 B 59 B
00000027.meta gzip 116 B 116 B
00000028.meta gzip 325 kB 325 kB
00000029.meta gzip 371 kB 371 kB
00000030.sst gzip 51.6 kB 52.8 kB 🔴 +1.19 kB (+2%)
00000031.sst gzip 1.38 MB 1.4 MB 🔴 +14.7 kB (+1%)
00000032.sst gzip 59 B 59 B
00000033.meta gzip 116 B 116 B
00000034.meta gzip 325 kB 325 kB
00000035.meta gzip 371 kB 371 kB
00000036.sst gzip 52.3 kB 53.3 kB 🔴 +966 B (+2%)
00000037.sst gzip 1.38 MB 1.4 MB 🔴 +14.7 kB (+1%)
00000038.sst gzip 59 B 59 B
00000039.meta gzip 116 B 116 B
00000040.meta gzip 325 kB 325 kB
00000041.meta gzip 371 kB 371 kB
CURRENT gzip 24 B 24 B
LOG gzip 668 B 667 B
Total 80.2 MB 80.2 MB ⚠️ +29.9 kB

📦 Webpack

Client

Main Bundles
Canary PR Change
3322-HASH.js gzip 65.8 kB N/A -
4191.HASH.js gzip 169 B N/A -
7920-HASH.js gzip 4.67 kB N/A -
9784-HASH.js gzip 5.63 kB N/A -
b1ad9f4c-HASH.js gzip 63.2 kB N/A -
framework-HASH.js gzip 59.7 kB 59.7 kB
main-app-HASH.js gzip 252 B 253 B
main-HASH.js gzip 40.1 kB 40.1 kB
webpack-HASH.js gzip 1.68 kB 1.68 kB
3577.HASH.js gzip N/A 168 B -
578-HASH.js gzip N/A 66.5 kB -
8590-HASH.js gzip N/A 5.61 kB -
9750-HASH.js gzip N/A 4.68 kB -
a8984546-HASH.js gzip N/A 63.2 kB -
Total 241 kB 242 kB ⚠️ +646 B
Polyfills
Canary PR Change
polyfills-HASH.js gzip 39.4 kB 39.4 kB
Total 39.4 kB 39.4 kB
Pages
Canary PR Change
_app-HASH.js gzip 194 B 193 B
_error-HASH.js gzip 181 B 182 B
css-HASH.js gzip 334 B 331 B
dynamic-HASH.js gzip 1.81 kB 1.81 kB
edge-ssr-HASH.js gzip 255 B 253 B
head-HASH.js gzip 349 B 351 B
hooks-HASH.js gzip 382 B 384 B
image-HASH.js gzip 581 B 582 B
index-HASH.js gzip 260 B 259 B
link-HASH.js gzip 2.48 kB 2.48 kB
routerDirect..HASH.js gzip 317 B 318 B
script-HASH.js gzip 384 B 386 B
withRouter-HASH.js gzip 316 B 315 B
1afbb74e6ecf..834.css gzip 106 B 106 B
Total 7.95 kB 7.96 kB ⚠️ +4 B

Server

Edge SSR
Canary PR Change
edge-ssr.js gzip 129 kB 129 kB
page.js gzip 294 kB 295 kB
Total 423 kB 424 kB ⚠️ +502 B
Middleware
Canary PR Change
middleware-b..fest.js gzip 618 B 615 B
middleware-r..fest.js gzip 156 B 156 B
middleware.js gzip 45.8 kB 45.4 kB
edge-runtime..pack.js gzip 842 B 842 B
Total 47.4 kB 47 kB ✅ -401 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 717 B 718 B
Total 717 B 718 B ⚠️ +1 B
Build Cache
Canary PR Change
0.pack gzip 4.8 MB 4.8 MB
index.pack gzip 123 kB 123 kB
index.pack.old gzip 123 kB 123 kB
Total 5.05 MB 5.05 MB ✅ -2.75 kB

🔄 Shared (bundler-independent)

Runtimes
Canary PR Change
app-page-exp...dev.js gzip 375 kB 375 kB
app-page-exp..prod.js gzip 207 kB 207 kB
app-page-tur...dev.js gzip 374 kB 374 kB
app-page-tur..prod.js gzip 207 kB 207 kB
app-page-tur...dev.js gzip 370 kB 370 kB
app-page-tur..prod.js gzip 204 kB 204 kB
app-page.run...dev.js gzip 371 kB 371 kB
app-page.run..prod.js gzip 205 kB 205 kB
app-route-ex...dev.js gzip 83.4 kB 83.4 kB
app-route-ex..prod.js gzip 56.4 kB 56.4 kB
app-route-tu...dev.js gzip 83.4 kB 83.4 kB
app-route-tu..prod.js gzip 56.4 kB 56.4 kB
app-route-tu...dev.js gzip 83 kB 83 kB
app-route-tu..prod.js gzip 56.2 kB 56.2 kB
app-route.ru...dev.js gzip 82.9 kB 82.9 kB
app-route.ru..prod.js gzip 56.2 kB 56.2 kB
dev-validati...dev.js gzip 133 kB 133 kB
dev-validati...dev.js gzip 133 kB 133 kB
dev-validati...dev.js gzip 131 kB 131 kB
dev-validati...dev.js gzip 131 kB 131 kB
dist_client_...dev.js gzip 324 B 324 B
dist_client_...dev.js gzip 326 B 326 B
dist_client_...dev.js gzip 318 B 318 B
dist_client_...dev.js gzip 317 B 317 B
pages-api-tu...dev.js gzip 46.1 kB 46.1 kB
pages-api-tu..prod.js gzip 34.3 kB 34.3 kB
pages-api.ru...dev.js gzip 46.1 kB 46.1 kB
pages-api.ru..prod.js gzip 34.3 kB 34.3 kB
pages-turbo....dev.js gzip 54.9 kB 54.9 kB
pages-turbo...prod.js gzip 39.9 kB 39.9 kB
pages.runtim...dev.js gzip 54.9 kB 54.9 kB
pages.runtim..prod.js gzip 39.9 kB 39.9 kB
server.runti..prod.js gzip 67 kB 67 kB
use-cache-pr...dev.js gzip 72.5 kB 72.5 kB
use-cache-pr...dev.js gzip 72.5 kB 72.5 kB
use-cache-pr...dev.js gzip 70.7 kB 70.7 kB
use-cache-pr...dev.js gzip 70.7 kB 70.7 kB
Total 4.1 MB 4.1 MB
📎 Tarball URL
https://vercel-packages.vercel.app/next/commits/01a3e986b9da8ec92255b46d40b4af1aa95eda69/next

Commit: 01a3e98

Comment thread crates/next-custom-transforms/src/react_compiler.rs Outdated
@marcoshernanz

Copy link
Copy Markdown
Contributor Author

Upstream follow-up is now open as swc-project/swc#12105. I compared SWC\047s existing \140is_required\140 against this PR\047s conservative predicate on the full v0 corpus. The existing SWC heuristic is not safe as a skip gate: it missed 10 of 257 actually transformed modules (nine \140forwardRef\140 modules plus one member-hook module). The new upstream \140may_require\140 had zero false negatives, selected the same 315 files as this PR, and was 1.52% faster than the local visitor across five detector-only runs. It also moves the Node binding to the conservative contract and treats parse failures conservatively. This Next.js draft should keep the local implementation until the SWC crate release containing that API is available, then switch both Turbopack and next-napi to the upstream predicate and delete the duplicate.

Comment thread crates/next-core/src/next_server/context.rs Outdated
Comment thread crates/next-custom-transforms/src/react_compiler.rs Outdated
kdy1 pushed a commit to swc-project/swc that referenced this pull request Aug 8, 2026
## Description

This fixes false negatives in the existing React Compiler
`fast_check::is_required` predicate and documents its conservative
skip-gate contract.

Before this PR, `is_required` was a low-false-positive heuristic, but it
was not safe for callers that skip React Compiler when it returns
`false`. On the real v0 corpus it missed anonymous `forwardRef`
callbacks and a module using member hook calls. This PR improves the
existing method rather than adding a second public predicate, following
maintainer feedback.

The new implementation allows false positives but not false negatives:
`false` means compilation cannot change the program. It scans every
function context for JSX, actual hook calls matching React Compiler
HIR's own hook-name rule, member hook calls, and opt-in/dynamic-gating
directives in real directive prologues.

The Node `isReactCompilerRequired{,Sync}` APIs continue to call
`is_required`. Fatal and recovered parse errors return `true`, because
an unsuccessful fixed-syntax parse cannot prove that compilation is
unnecessary.

The package test command enumerates both test files explicitly so it
remains compatible with the existing Windows + Node 18 CI job.

## v0 correctness corpus

I benchmarked a fixed v0 checkout
(`1ab042a47c053bf5ddad5ffb9c6af153ce8e5b56`) on a 16-vCPU / 32-GB Vercel
DevBox:

- 1,816 tracked JS/TS source files
- 10,464,109 source bytes
- zero parser failures
- 257 modules actually transformed by the Rust React Compiler
- 67 compiler diagnostics

The harness parses the corpus once, runs detectors repeatedly, and uses
the actual compiler result as ground truth. It asserts that gated and
ungated transformed paths are identical.

| Detector | Selected files | False negatives |
| --- | ---: | ---: |
| `is_required` before this PR | 279 | 10 / 257 (3.89%) |
| Current Next.js conservative visitor | 315 | 0 / 257 |
| This PR: improved `is_required` | **302** | **0 / 257** |

The old implementation missed nine real `React.forwardRef` UI modules
and one hook module using `React.useState` / `React.useEffect`. The
improved implementation retains all 257 transforms while rejecting 13
more false positives than the current Next.js visitor.

## End-to-end compiler effect

A fresh optimized release run after applying all review feedback used
five interleaved gated/ungated samples on the exact corpus:

| Pipeline | Median | Transformed modules |
| --- | ---: | ---: |
| No gate | 2,371.956 ms | 257 |
| Improved `is_required` gate | **1,906.180 ms** | 257 |

That removes **465.776 ms / 19.64%** from the React Compiler pipeline on
the real v0 corpus without changing compiler output. The detector itself
took 20.624 ms for the full 10.46-MB corpus (mean of 100 passes).

The temporary synthetic CodSpeed benchmark was removed at review
request. The performance evidence remains the real v0 corpus with actual
compiler output as the correctness oracle.

## Review feedback incorporated

- Improved the existing `is_required` API instead of introducing
`may_require`.
- Detect hooks only at call sites and reuse React Compiler's
`is_hook_name` rule (`use` plus uppercase ASCII or a digit).
- Restrict opt-in strings to leading directive prologues using
`Stmt::can_precede_directive`.
- Treat both fatal and recovered parser errors conservatively in the
Node binding.
- Added actual-compiler regressions proving name-only and JSX-free
`React.createElement` wrapper cases do not compile.
- Removed the synthetic benchmark and changed the changeset from a minor
feature to a patch fix.

## Validation

- `cargo fmt --all -- --check`
- `cargo test -p swc_ecma_react_compiler` (107 unit tests + 15 fixtures)
- `cargo test -p binding_react_compiler_node` (14 passed)
- `cargo clippy -p swc_ecma_react_compiler -p
binding_react_compiler_node --all-targets -- -D warnings`
- `pnpm --filter @swc/react-compiler build:dev`
- `pnpm --filter @swc/react-compiler test` (8/8)
- Earlier full-PR validation: `cargo clippy --all --all-targets -- -D
warnings`; `packages/core: pnpm build:dev && pnpm test` (117 passed, 3
skipped)
- Final GPT-5.6 Sol xhigh + Claude Opus 5 xhigh autoreview panel: zero
findings, “patch is correct” (0.99 confidence)

Follow-up to
[vercel/next.js#96820](vercel/next.js#96820).
@datadog-official

This comment has been minimized.

@marcoshernanz

Copy link
Copy Markdown
Contributor Author

This is ready for final maintainer review/merge from the implementation and CI side.

  • consumes the released SWC React Compiler fast_check::is_required API and removes the duplicate Next.js predicates
  • preserves explicit annotation/all semantics and fail-open behavior on every native read/parse failure
  • retains the browser-only App Router scope requested in review
  • aligns Next.js and the official MDX fork on one SWC 76 stack, with the React Compiler dependency excluded from WASI
  • final v0 corpus result: 257/257 transforming modules retained, zero false negatives, and a 19.64% reduction in the measured compiler pipeline
  • all review threads resolved; final GPT-5.6 Sol + Claude Opus 5 xhigh autoreview clean at 0.98 confidence each
  • fresh CI on c18d747464: 114 passed, 17 intentionally skipped, 0 failed (the unrelated navigation timing failure passed its isolated rerun)

The PR is mergeable with current canary. It remains a draft/review-required PR, so maintainer approval and the normal ready-for-review state transition are the only remaining gates.

@marcoshernanz
marcoshernanz marked this pull request as ready for review August 10, 2026 18:50
Comment thread crates/next-napi-bindings/src/react_compiler.rs Outdated
Comment thread turbopack/crates/turbopack-ecmascript/src/transform/mod.rs
@marcoshernanz

Copy link
Copy Markdown
Contributor Author

Luke review follow-up is complete in signed commit 01a3e98.

Changes:

  • Missing files and fatal SWC parse failures now skip React Compiler. Recovered parser diagnostics remain fail-open because SWC produced an AST and Babel parser behavior can differ.
  • The pre-conversion gate now handles every compilation mode explicitly: infer uses SWC fast_check::is_required, annotation recursively scans real function directive prologues for use memo / legacy use forget, and all remains unconditional.
  • Annotation coverage includes nested functions, misplaced and module-level directives, dynamic-gating directives under the current dynamic_gating: None options, JSX/hook-only negatives, and all-mode behavior.

Verification:

  • cargo fmt --all -- --check
  • cargo clippy -p turbopack-ecmascript --lib --tests -- -D warnings -A deprecated
  • cargo test -p turbopack-ecmascript --lib react_compiler_tests: 4/4
  • cargo test -p turbopack-tests --test react_compiler: 3/3
  • cargo check -p next-napi-bindings
  • GPT-5.6 Sol xhigh + Claude Opus 5 xhigh autoreview: 0 findings, patch correct at 0.98 confidence
  • Fresh GitHub CI: 115 passed, 17 intentional skips, 0 pending/failing. One unrelated app-action test process hung until the fixed 30-minute job timeout; the preserved-cache isolated retry passed in 2m56s.

All review threads are resolved, Luke approval remains valid, and GitHub reports MERGEABLE / CLEAN. Ready to merge.

@lukesandberg
lukesandberg merged commit e0941e6 into canary Aug 10, 2026
232 of 234 checks passed
@lukesandberg
lukesandberg deleted the codex/turbopack-rust-react-compiler-scope branch August 10, 2026 22:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants