Skip to content

chore(sample-apps): upgrade react-router from v6 to v8 - #2358

Merged
oliverlaz merged 7 commits into
mainfrom
react-router-v6-v8-upgrade-50af8c
Aug 6, 2026
Merged

chore(sample-apps): upgrade react-router from v6 to v8#2358
oliverlaz merged 7 commits into
mainfrom
react-router-v6-v8-upgrade-50af8c

Conversation

@oliverlaz

@oliverlaz oliverlaz commented Aug 5, 2026

Copy link
Copy Markdown
Member

💡 Overview

Upgrades zoom-clone, livestream-app, audio-rooms and messenger-clone from react-router-dom@6 to react-router@8, in two steps per the official guides (v6 → v7, v7 → v8).

No route code changes were needed. The only source edits are import paths (react-router-domreact-router, RouterProvider from react-router/dom). None of the apps use multi-segment splat routes, fetchers, fallbackElement, actions, match.data or meta, so no future-flag or dataloaderData migration applied.

📝 Implementation notes

Most of this diff is the React bump that react-router@8 forces: it peers on react >=19.2.7 and the monorepo pinned 19.2.3. All non-React-Native workspaces move to 19.2.8; RN stays on 19.2.3 (react-native@0.86.2 peers on ^19.2.3).

Two things look odd and are load-bearing:

Important

react/react-dom in the root devDependencies — the root doesn't import React. The entry pins which copy yarn hoists, since a root dependency must resolve from root node_modules. Without it yarn keeps 19.2.3 at the root (the RN ecosystem outweighs the web side in dependent count), every web workspace gets a nested 19.2.8, and an app plus the workspace-linked SDK load two React instances — every SDK component using hooks throws Invalid hook call.

moduleNameMapper in packages/react-native-sdk/jest.config.jsvideo-react-bindings is shared by web and RN, so its single copy resolves one React version. With the root on 19.2.8 the RN tests would load bindings' 19.2.8 next to that package's 19.2.3 and fail with more than one copy of React. While the two platforms sit on different versions, one side needs an override; this keeps it in test-only config.

Pinning React at the root also de-hoisted react-native, react-native-gesture-handler and babel-preset-expo, breaking three things in the RN SDK test setup that assumed root hoisting: the react-native jest preset shim (now @react-native/jest-preset, declared explicitly), a hardcoded <rootDir>/../../node_modules path (now require.resolve), and expo-module-scripts' relative sibling lookup of babel-preset-expo (third-party, so that package is pinned at the root).

Merged main for #2359. Note it had bumped react-router-dom to ^6.30.4 in these apps; conflicts are resolved to react-router ^8.3.0, and react-router-dom is gone from every manifest and the lockfile.

✅ Verification

lint:ci:all (0 errors) · test:ci:all (844 passed) · test:react-native:sdk (124 tests) · NODE_ENV=production build:all · install --immutable.

Every route and nav primitive exercised per app in a browser, with real calls joined against the demo backend. react-dogfood checked. React Native dogfood rebuilt and re-run on a physical iPhone, since the hoisting change affects RN resolution.

⚠️ Pre-existing, not fixed here

zoom-clone's /call/<unknown> dead-ends on an empty outlet — its * child renders <Navigate to="/">, whose loader redirects to /call/lobby with no callId, matching * again. Verified identical on the v6 baseline, so not upgrade fallout.

🎫 Ticket: https://linear.app/stream/issue/REACT-1053/upgrade-react-router-in-react-sample-apps-from-v6-to-v8

📑 Docs: n/a — sample apps only, no public API change

Summary by CodeRabbit

  • Bug Fixes

    • Updated multiple apps and packages to newer React and routing versions for improved compatibility and stability.
    • Standardized routing imports across sample apps to keep navigation behavior consistent.
  • Chores

    • Adjusted repository ignore settings for local tooling files.
    • Updated test setup for React Native packages to work with current presets and avoid duplicate React instances.

Replaces react-router-dom@6 with react-router@7 in the zoom-clone,
livestream-app, audio-rooms and messenger-clone React sample apps.

- react-router-dom is no longer needed in v7; imports now come from
  react-router, with RouterProvider from react-router/dom
- no future-flag migrations were required: none of the apps use
  multi-segment splat routes, React.lazy in component scope, fetchers,
  formMethod comparisons, fallbackElement or the deprecated
  json()/defer() helpers
Prepares for react-router v8, which peers on react >=19.2.7. Every
non-RN workspace moves from 19.2.3 to 19.2.8 so that a workspace-linked
package and its consumer always agree on the react version - otherwise
an app and the video SDK load two separate react instances and every
SDK component using hooks throws "Invalid hook call".

React Native stays on 19.2.3: react-native@0.86.2 peers on ^19.2.3 and
the RN packages and apps now get their own nested copy.

The root react/react-dom devDependencies are not imported by the root
workspace - they exist to pin which copy yarn hoists. Yarn hoists a
single react version chosen by dependent count across the whole graph,
and the RN ecosystem outweighs the web side, so without this entry
19.2.3 stays at the root and every web workspace gets a nested 19.2.8
duplicate. A resolutions entry would also pin it but would force RN
off 19.2.3 too.
Bumps react-router from 7.18.2 to 8.3.0 in the zoom-clone,
livestream-app, audio-rooms and messenger-clone React sample apps.

No route code changes were needed: none of the apps read match.data or
define meta functions, so there is no data -> loaderData migration, and
no loader uses the context argument that future.v8_middleware changes.
The remaining v8 flags are framework-mode only, and react-router-dom
was already dropped during the v7 upgrade.
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c9912d3e-f4e0-4aa5-ab3c-b6f3eb376b60

📥 Commits

Reviewing files that changed from the base of the PR and between 1469f96 and 225d847.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (3)
  • package.json
  • packages/react-native-sdk/expo-config-plugin/jest.config.js
  • packages/react-native-sdk/package.json
💤 Files with no reviewable changes (1)
  • package.json

📝 Walkthrough

Walkthrough

The pull request upgrades React and React DOM to 19.2.8, migrates four React sample apps from react-router-dom to react-router 8.3.0, updates React Native Jest configuration, and ignores .claude/launch.json.

Changes

React dependency and router migration

Layer / File(s) Summary
React dependency baseline
package.json, packages/*/package.json, sample-apps/react/*/package.json
React and React DOM versions are updated to 19.2.8.
Audio rooms router migration
sample-apps/react/audio-rooms/...
The app replaces react-router-dom with react-router 8.3.0 and updates routing imports.
Livestream router migration
sample-apps/react/livestream-app/...
The app replaces react-router-dom with react-router 8.3.0 and updates routing imports.
Messenger router migration
sample-apps/react/messenger-clone/...
The app replaces react-router-dom with react-router 8.3.0 and updates routing imports.
Zoom router migration
sample-apps/react/zoom-clone/...
The app replaces react-router-dom with react-router 8.3.0 and updates routing imports.

React Native Jest configuration

Layer / File(s) Summary
Jest preset and React resolution
packages/react-native-sdk/package.json, packages/react-native-sdk/jest.config.js, packages/react-native-sdk/expo-config-plugin/jest.config.js
The SDK uses @react-native/jest-preset, configures the Expo plugin explicitly, resolves gesture-handler setup with require.resolve, and maps React modules locally.

Repository ignore rule

Layer / File(s) Summary
Ignore Claude launch configuration
.gitignore
.claude/launch.json is added to the ignored files.

Estimated code review effort: 2 (Simple) | ~15 minutes

Suggested reviewers: santhoshvai

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the primary change: upgrading React Router in the sample apps from v6 to v8.
Description check ✅ Passed The description includes the required overview, implementation notes, ticket, documentation status, and detailed verification results.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch react-router-v6-v8-upgrade-50af8c

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@oliverlaz
oliverlaz requested a review from jdimovska August 5, 2026 09:53
… root pin

Pinning react at the root moved react-native, react-native-gesture-handler
and babel-preset-expo out of the root node_modules into per-workspace
copies, which broke three things that silently relied on them being
hoisted:

- preset: 'react-native' is a shim that requires @react-native/jest-preset,
  which was never a declared dependency. It is now declared and referenced
  directly.
- setupFilesAfterEnv pointed at a hardcoded <rootDir>/../../node_modules
  path for the gesture-handler jest setup; it now uses require.resolve.
- expo-module-scripts/babel.config.base.cjs resolves babel-preset-expo via
  a relative sibling path, so babel-preset-expo is pinned at the root to
  keep it next to expo-module-scripts.

The jest moduleNameMapper is the one addition that is not a hoisting
artifact: video-react-bindings is shared by web and React Native, so its
single copy resolves one react version. With the root on 19.2.8 the RN
tests would otherwise load bindings' 19.2.8 alongside this package's
19.2.3 and fail with "more than one copy of React".
Brings in the dependency-range alignment from #2359, which fixes the 20
@typescript-eslint no-shadow errors that were failing lint on main and
therefore on this branch.

Conflicts were all in manifests this branch also touches. Resolved by
taking main's aligned ranges wholesale and re-applying only this
branch's deliberate overrides:

- react/react-dom 19.2.8 in the non-React-Native workspaces, plus the
  root pins that keep 19.2.8 hoisted
- react-router ^8.3.0 in the four upgraded sample apps, replacing the
  react-router-dom ^6.30.4 that main had bumped
- babel-preset-expo pinned at the root

Everything else - eslint 9.39.5, prettier 3.9.6, nx 22.7.8,
@types/react ~19.2.18 and the rest of the 95 aligned ranges - comes
from main unchanged.
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

Bundle size

Built package output. Sizes in KB; delta vs main@5ae2dfe.

No significant package size increase vs main.

…n tests

expo-module-scripts was a single devDependency used by exactly one file,
expo-config-plugin/jest.config.js, which re-exported its 12-line
jest-preset-plugin. Only testEnvironment, testRegex and the babel transform
were doing anything there: the plugin tests are plain node TypeScript with no
snapshots and no JSX, so the jest-watch-typeahead watch plugins and the
prettier@2 prettierPath were dead weight.

In exchange it pulled in @babel/cli, jest-expo, eslint-config-universe,
ts-jest, prettier@2 and a second @react-native/jest-preset at 0.85.3, which
mismatched the 0.86.2 this package already declares directly.

The preset also resolved babel-preset-expo through a relative sibling path in
babel.config.base.cjs, which was the only reason babel-preset-expo was pinned
at the repo root. Removing it lets that pin go too, which clears the YN0002
warning about the root not providing react-refresh, a non-optional peer
dependency of babel-preset-expo. The two Expo sample apps keep their own
copies via their own expo dependency.

Verified: 97 plugin tests and the full react-native-sdk suite and type check
pass, bob build succeeds, and the only yarn install warning that disappears
is the YN0002 line.
@oliverlaz
oliverlaz merged commit 897f2f1 into main Aug 6, 2026
21 checks passed
@oliverlaz
oliverlaz deleted the react-router-v6-v8-upgrade-50af8c branch August 6, 2026 07:55
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.

3 participants