Skip to content

EPBDS-16211 React 19: declare it, and gate it like 16 and 17 - #131

Merged
AlexSamBY merged 1 commit into
masterfrom
react-19-flip
Sep 30, 2026
Merged

AlexSamBY merged 1 commit into
masterfrom
react-19-flip

Conversation

@AlexSamBY

@AlexSamBY AlexSamBY commented Sep 30, 2026 •

Copy link
Copy Markdown
Member

On master since #130 merged, which fixed the npm install peer conflict this change needed gone to add a devDependency. The rebased tree is identical to the one the local gates below ran on.

The flip

peerDependencies: react and react-dom now read ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0. The range is widened additively, so hosts on 16.14, 17 and 18 change nothing. This closes §8's fast path:

How 19 is gated, in three matrices

16.14 17 18 19
whole jest suite test:react16 test:react17 npx jest / test:coverage test:react19 (new)
packed artifact server-rendered test:pack:peers test:pack:peers test:pack:consumer test:pack:peers (added 19.3.0)
published .d.ts compiled test:types test:types test:types test:types (added @types/react 19.3.0)
  • The suite on React 19 is a fixture leg, like 16.14 and 17. scripts/fixtures/react19 is an install-only package pinning react/react-dom 19.3.0. Plain npm ci nests it, it is mapped in at resolve time, and npm run test:react19 runs it locally too. The harness still asserts the loaded React (19.3.0) and scheduler (0.28) in every worker.
  • What differs for 19. React 19 has no legacy root and ships react-dom/client, so the leg renders through createRoot as the default suite does. floors.js records legacyRoot: false, which skips three things that exist only for 16/17: the RTL legacyRoot patch, the ReactDOM.render assertion and the react-dom/client stub.
  • CI. The new react-19 job replaces the continue-on-error react-19-advisory job, which installed React 19 over the lock with --legacy-peer-deps; the new job needs neither. No required checks are configured on master today, so react-19 gates exactly as react-16-floor and react-17 do. If branch protection ever named react-19-advisory, it should name react-19 now.
  • Types. The published declarations compile against @types/react 19, with both the interop default import and the direct CommonJS import. That matters because 19 removed the global JSX namespace. gen-ts stays on the dev tree's 18; the plan's "pin @types/react@19 for gen-ts" item was written assuming the dev tree would move to 19, and it does not.

Docs

  • README and the demo's docs page state the new range.
  • The demo's changelog (Unreleased) says React 19 is supported and how it is tested. It also records EPBDS-16211 G: compile JSX with the automatic runtime #129's change: the bundle imports react/jsx-runtime from the host's React, which a host that aliases react to one copy has to alias too. Two older Unreleased paragraphs that said the range was not widened yet are updated, so the section does not contradict itself.
  • CLAUDE.md lists the three React legs.
  • The plan closes §8's gate 4, the CI-coverage row, the gen-ts row, the Appendix C "React 19 flip" checklist and §10's Phase 7 React 19 item.

Gates

All exited 0:

  • lint:js, lint:css, typecheck, typecheck:contract;
  • css:fixture:check, docs:props:check, docs:views:check;
  • test:env-flags, test:types, test:coverage, build;
  • test:pack, test:pack:peers (16.14.0, 17.0.2, 19.3.0);
  • test:react16, test:react17, test:react19, 2907 tests on each, as on 18;
  • test:e2e, 41 Playwright tests;
  • the manifest contract.

Two first runs lost a jest worker to SIGSEGV, each killing one suite before its tests ran: test:react19 once and test:react17 once. That is the Node 24 V8 garbage-collector crash (nodejs/node#62393), fixed on v24.x-staging but not in a release yet. Both passed 2907/2907 on rerun. CI runs Linux, where it has not been seen.

🤖 Generated with Claude Code

Base automatically changed from fix-react-refresh-peer to master September 30, 2026 12:34
The peers now read `^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0`, widened
additively, so hosts on 16.14, 17 and 18 change nothing. §8's fast path is
complete: gates 1 and 3 were met, gate 2 lapsed with the dependency trim, and
this is gate 4.

- The suite. React 19.3.0 is a fixture leg like the 16.14 and 17 ones: an
  install-only package (scripts/fixtures/react19) that plain `npm ci` nests,
  mapped in at resolve time, and `npm run test:react19` runs it locally.
  The harness self-checks the loaded version in every worker, as before.
  React 19 has no legacy root and ships react-dom/client, so this leg renders
  through createRoot: floors.js records `legacyRoot: false`, which skips the
  RTL patch, the ReactDOM.render assertion and the react-dom/client stub.
- CI. `react-19` replaces the `continue-on-error` `react-19-advisory` job,
  which installed 19 over the lock with --legacy-peer-deps. The new job
  needs neither.
- The packed artifact. `test:pack:peers` now server-renders it on 16.14.0,
  17.0.2 and 19.3.0; `test:pack:consumer` covers 18.3.1.
- The types. `test:types` compiles the published declarations against
  @types/react 19 as well, both import styles; 19 is the version that
  removed the global JSX namespace. gen-ts stays on the dev tree's 18.

README, the demo's docs and changelog, CLAUDE.md and the plan record it. The
changelog also records #129's `react/jsx-runtime` import, which a host that
aliases `react` can see.

Local gates exit 0: the React 18, 16, 17 and 19 legs pass 2907 tests each.
Two first runs lost a worker to SIGSEGV (the Node 24 V8 crash,
nodejs/node#62393): test:react19 once and test:react17 once. Both passed
2907/2907 on rerun.
@AlexSamBY
AlexSamBY merged commit 5ede721 into master Sep 30, 2026
5 checks passed
@AlexSamBY
AlexSamBY deleted the react-19-flip branch September 30, 2026 12:39
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.

1 participant