Skip to content

Add React 19.3 adoption codemods and recipe - #8

Merged
mohebifar merged 3 commits into
mainfrom
claude/wonderful-davinci-b7ago1
Sep 10, 2026
Merged

mohebifar merged 3 commits into
mainfrom
claude/wonderful-davinci-b7ago1

Conversation

@mohebifar

@mohebifar mohebifar commented Sep 10, 2026

Copy link
Copy Markdown
Member

Summary

React 19.3 (release post) has no breaking changes, so these are adoption codemods: they move code from experimental names and pre-19.3 workarounds onto the stable APIs.

New packages under codemods/:

Package What it does
react-19-3-unprefix-stable-apis Renames unstable_ViewTransition, unstable_addTransitionType (19.3), unstable_Activity, experimental_useEffectEvent (19.2) to their stable names. Covers named imports with/without aliases, React.unstable_X member access and JSX member tags, CJS require("react") destructuring, re-exports, and all usage sites. Keeps the old local name when the stable name is already taken in the file. Leaves unstable_startGestureTransition alone.
react-19-3-use-browser Rewrites the useState(false) + useEffect(() => setMounted(true), []) + if (!mounted) return <Fallback /> idiom into use(browser()) from react-dom. The component is split so the old early return becomes a <Suspense fallback> in a wrapper that keeps the original name and export; the inner component calls use(browser()). Handles function declarations, arrow components (including FC<Props> annotations), destructured props, namespace hook access (React.useStateReact.use / React.Suspense), and cleans up unused useState / useEffect / useLayoutEffect imports. Bails when the flag is used elsewhere or the fallback references destructured props.
react-19-3-fragment-ref-wrappers Replaces <div ref={r} style={{ display: "contents" }}> / <span …> wrappers with <Fragment ref={r}>. Only fires when every use of the ref in the file is its declaration, this wrapper's ref prop, or r.current.<FragmentInstance method>. Adds a Fragment import (or uses React.Fragment) as needed, keeping a leading "use client" directive first.
react-19-3-migration-recipe Chains the three above plus the existing react-19-remove-context-provider.

Also: lockfile importer entries for the new workspace packages, and root README sections.

Test plan

  • CI: pnpm run check-types passes for all packages.
  • CI: JSSG snapshot tests pass for the three new transforms (10 / 9 / 8 fixtures, including no-change cases for shadowed names, other modules, unsupported ref usage, and extra props), and the recipe metadata tests pass.
  • All pre-existing codemod suites still pass.

Note: the session that authored this could not reach the npm registry, so the fixtures were traced by hand and first executed in CI. The only correction needed was a trailing newline in the metrics.json fixtures.

🤖 Generated with Claude Code

https://claude.ai/code/session_01C1zn9AbvKVCERf15x3zJ68

claude and others added 3 commits September 10, 2026 19:42
Add three JSSG codemods for the APIs that stabilized in React 19.3
(plus the 19.2 leftovers), and a recipe that chains them:

- react-19-3-unprefix-stable-apis: rename unstable_ViewTransition,
  unstable_addTransitionType, unstable_Activity and
  experimental_useEffectEvent to their stable names across ESM and
  CJS imports, member access, JSX tags, re-exports and usage sites.
- react-19-3-use-browser: replace the useState(false) + useEffect
  mounted-state pattern with use(browser()) from react-dom, splitting
  the component so the old early return becomes a Suspense fallback.
- react-19-3-fragment-ref-wrappers: replace display:contents wrapper
  elements that only hold a ref with <Fragment ref>, guarded by a
  check that every ref usage is on the FragmentInstance API.
- react-19-3-migration-recipe: runs the above together with
  react-19-remove-context-provider.

Also add the lockfile importer entries for the new workspace packages
and list the codemods in the root README.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C1zn9AbvKVCERf15x3zJ68
The JSSG test runner compares metrics.json byte for byte and the
existing fixtures have no trailing newline.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C1zn9AbvKVCERf15x3zJ68
@mohebifar
mohebifar merged commit 9288679 into main Sep 10, 2026
1 check passed
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