Skip to content

Upgrade the example app to Expo SDK 57 - #293

Merged
majkpal merged 3 commits into
software-mansion:mainfrom
majkpal:chore/upgrade-expo-sdk-57
Aug 31, 2026
Merged

majkpal merged 3 commits into
software-mansion:mainfrom
majkpal:chore/upgrade-expo-sdk-57

Conversation

@majkpal

@majkpal majkpal commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Moves examples/react-native/WhipWhepDemo from Expo SDK 54 to SDK 57. This is what Dependabot #284–#287 were really asking for — RN 0.81.4 → 0.86.3, React 19.1 → 19.2.3, reanimated 4.1 → 4.5.1 and worklets 0.5.1 → 0.10.1 are all just the SDK 57 matrix — and it closes out the "left behind" list on #292.

Stacked on #292. The first commit here is that PR; review only 4fbc127. Happy to rebase once #292 lands.

What expo install --fix did

expo@^57, and with it expo-audio, expo-camera, expo-constants, expo-font, expo-keep-awake, expo-linking, expo-router, expo-splash-screen, expo-status-bar, expo-system-ui, expo-web-browser (all now on unified ~57.x), plus react/react-dom 19.2.3, react-native 0.86.3, react-native-gesture-handler ~2.32, react-native-reanimated 4.5.1, react-native-safe-area-context ~5.7, react-native-screens ~4.26, react-native-worklets 0.10.1, @types/react ~19.2.4, typescript ~6.0.3, jest-expo ~57.0.5. app.json gained the expo-splash-screen and expo-status-bar config plugins that SDK 57 requires. Alongside it: jest 30, @types/jest 30 (jest-expo@57 needs them), react-test-renderer 19.2.3 to match React 19, and @react-native/eslint-config ^0.86.3.

What the upgrade actually needed on top

Each of these was a hard failure, not a tidy-up:

  • expo-module-scripts ~4.0.5 → ~56.0.3. Not optional. 4.0.5 depends on babel-preset-expo ~12, which hoists to the workspace root and shadows the copy expo@57 ships, so Metro fails bundling react-native itself: Unable to determine event arguments for "onModeChange". 56.0.3 dropped that dependency.
  • babel-preset-expo added to the example's devDependencies. Once nothing hoists it to the root, @expo/metro-config can't resolve it from there: Cannot find module 'babel-preset-expo'.
  • Type-only imports and re-exports in packages/react-native-client. The tsconfig expo-module-scripts 56 brings turns on verbatimModuleSyntax, isolatedModules and strict. 28 of the 30 resulting errors are mechanical (import type / export type).
  • iOS deployment target. The config plugin wrote ios.deploymentTarget unconditionally, downgrading the Expo template's own default (16.4 on SDK 57) to this SDK's 15.1 minimum, which left CocoaPods unable to resolve the Expo pod. It now only raises an existing lower value, and still honours an explicit iphoneDeploymentTarget. The example's app.json no longer pins 15.1 for the same reason.
  • useColorScheme(). RN 0.86 widened it to include 'unspecified' and made it non-nullable, so Colors[colorScheme ?? 'light'] no longer type-checks. The example's own hook now collapses it to the two themes it defines.

Two real bugs the stricter config surfaced

Both pre-existing, both in the published SDK's types:

  • connect: (ConnectOptions) => Promise<void> on WhepClientViewRef named its parameter after its type, so the argument was silently any. Now connect: (options: ConnectOptions) => Promise<void>.
  • RNMobileWhipClientViewModule never declared whipPeerConnectionState, even though useWhipConnectionState reads it. Declared now, mirroring the WHEP module.

Worth a follow-up: neither whipPeerConnectionState nor whepPeerConnectionState actually exists as a native Property on either platform — only cameras does. Both hooks fall back to "unknown" via ?? and then track the change events, so behaviour is unaffected, but the exported whepPeerConnectionState const is permanently undefined. Out of scope here; left as-is rather than changing native behaviour in an upgrade PR.

On the ESM output

build/ now emits ESM rather than CommonJS. That matches how Expo's own SDK 57 modules ship — expo-camera and expo-web-browser both have main pointing at ESM with no "type": "module" — and Metro handles it. The config plugin under plugin/build stays CommonJS, which is what app.plugin.js requires. This resolves the concern I raised on #292.

Testing

  • yarn build ✅
  • yarn tsc ✅
  • yarn lint:check ✅ (only the gitignored, generated expo-env.d.ts)
  • yarn docs ✅ (same 4 pre-existing typedoc warnings)
  • npx expo export --platform ios ✅
  • npx expo prebuild --clean ✅ including pod install
  • iOS: xcodebuild -workspace WhipWhepDemo.xcworkspace -scheme WhipWhepDemo -destination 'platform=iOS Simulator,name=iPhone 17' → ** BUILD SUCCEEDED **
  • Android: ./gradlew :app:assembleDebug (JDK 17) → BUILD SUCCESSFUL

Not exercised: runtime behaviour against a live WHIP/WHEP server, and the iOS broadcast-extension screen-share path on a physical device. Both native example apps (examples/ios, examples/android) are untouched by this PR.

🤖 Generated with Claude Code

Copilot AI lite review requested due to automatic review settings August 28, 2026 13:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Upgrades the examples/react-native/WhipWhepDemo Expo app from SDK 54 to SDK 57 and aligns the workspace tooling/types with the stricter TypeScript / module settings brought in by newer Expo module tooling.

Changes:

  • Bump the example app to Expo SDK 57 (RN 0.86 / React 19.2) and update related Expo/RN dependencies.
  • Adjust react-native-client TS surface (type-only imports/exports and a connect signature fix) for stricter TS settings.
  • Update the iOS config plugin deployment-target logic to avoid downgrading Expo’s default deployment target.

Reviewed changes

Copilot reviewed 18 out of 19 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/react-native-client/src/ReactNativeMobileWhipClientViewModule.ts Type/import updates and native module typing change.
packages/react-native-client/src/ReactNativeMobileWhipClientView.tsx Convert several imports to type-only.
packages/react-native-client/src/ReactNativeMobileWhepClientView.tsx Convert several imports to type-only.
packages/react-native-client/src/ReactNativeMobileWhepClient.types.ts Fix connect parameter naming to avoid any.
packages/react-native-client/src/index.ts Split value export (VideoParameters) from type exports under stricter TS.
packages/react-native-client/src/hooks/useEventState.ts Use type-only import for payload typings.
packages/react-native-client/src/hooks/useEvent.ts Use type-only import for payload typings.
packages/react-native-client/src/hooks/useConnectionState.ts Use type-only imports for peer-connection state types.
packages/react-native-client/src/hooks/eventPayloadValidator.ts Use type-only import for payload typings.
packages/react-native-client/plugin/src/withWhipWhepIos.ts Avoid writing a low deployment target unless explicitly set / needed.
packages/react-native-client/package.json Update dev tooling deps (expo-module-scripts, typedoc, @types/react).
package.json Update repo-wide linting/tooling dependency versions.
examples/react-native/WhipWhepDemo/package.json Upgrade example app dependency matrix to SDK 57 + Jest 30 tooling.
examples/react-native/WhipWhepDemo/hooks/useThemeColor.ts Route theme selection through local useColorScheme wrapper.
examples/react-native/WhipWhepDemo/hooks/useColorScheme.ts New wrapper to collapse RN 0.86 useColorScheme() into app themes.
examples/react-native/WhipWhepDemo/app/(tabs)/_layout.tsx Consume the new useColorScheme wrapper for safe palette indexing.
examples/react-native/WhipWhepDemo/app.json Remove iOS deployment target pin; add required SDK 57 config plugins.
examples/react-native/WhipWhepDemo/.eslintrc Remove trailing comma for strict JSON parsing.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread examples/react-native/WhipWhepDemo/package.json Outdated
Copilot AI review requested due to automatic review settings August 28, 2026 13:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 20 changed files in this pull request and generated 1 comment.

Comment thread packages/react-native-client/plugin/src/withWhipWhepIos.ts Outdated
majkpal added a commit that referenced this pull request Aug 31, 2026
`yarn lint:check` runs `swift-format lint -s` for the `ios-client`
workspace, and under `-s` (strict) `TrailingWhitespace` is an error
rather than a warning. 26 lines across four files trip it, so the
`all_packages_lint` job fails.

**This is on `main`, not introduced by any open PR** — it currently
fails CI on every one of them. Reproduced on a clean `origin/main`
checkout: 26 errors, exactly the set CI reports.

```
Sources/ios-client/Capturers/BroadcastScreenShareCapturer.swift:100:1: error: [TrailingWhitespace] …
Sources/ios-client/ClientBase.swift:111:1: error: [TrailingWhitespace] …
… 24 more, in ClientBase.swift, WhepClient.swift and WhipClient.swift
```

The fix is just the workspace's own `yarn lint` (`swift-format format
-i`) — no hand edits.

## Why this is safe

- `git diff -w` on the commit is **empty**: nothing but whitespace
changed.
- Every one of the 26 removed lines was blank apart from its trailing
spaces, so nothing touches a string literal or any token. Compilation
cannot be affected.
- After it, `swift-format lint -r -s ./Sources --configuration
swift-format-config.json` reports 0 errors.

## Why `examples/ios` was never affected

The `ios_lint` workflow runs `swift-format format -i` *before*
`swift-format lint`, so it silently fixes the tree in the runner and
then lints the fixed copy. Only `all_packages_lint`, which goes through
`yarn lint:check`, actually enforces this — and it only covers
`packages/ios-client`.

Worth considering separately: having `ios_lint` format-then-lint means
it can never fail on formatting, which is presumably not the intent.

## Merge order

Kept standalone and based directly on `main` so it can go in ahead of
#291, #292 and #293 — all three go green once they pick it up. Happy to
cherry-pick it into #291 instead if you would rather not have a fourth
PR.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
majkpal and others added 2 commits August 31, 2026 11:17
Moves examples/react-native/WhipWhepDemo from SDK 54 to SDK 57, which is
what the four Dependabot PRs left open on software-mansion#292 were really asking for:
RN 0.81.4 -> 0.86.3, React 19.1 -> 19.2.3, reanimated 4.1 -> 4.5.1 and
worklets 0.5.1 -> 0.10.1 are all just the SDK 57 matrix.

Beyond `expo install --fix`, the upgrade needed:

- expo-module-scripts ~4.0.5 -> ~56.0.3. Not optional: 4.0.5 depends on
  babel-preset-expo ~12, which hoists to the workspace root and shadows
  the copy expo@57 ships, so Metro fails to bundle react-native itself
  ("Unable to determine event arguments for onModeChange"). 56.0.3 drops
  that dependency.
- babel-preset-expo added to the example's devDependencies. Once nothing
  hoists it to the root, @expo/metro-config can no longer resolve it from
  the workspace root.
- The tsconfig that expo-module-scripts 56 brings turns on
  verbatimModuleSyntax, isolatedModules and strict, so type-only imports
  and re-exports in packages/react-native-client are marked as such. The
  emitted build/ output becomes ESM, which is exactly how Expo's own SDK
  57 modules (expo-camera, expo-web-browser) ship - `main` pointing at
  ESM with no "type": "module" - and the config plugin under plugin/build
  stays CommonJS, which is what app.plugin.js needs.
- Two real type errors that the looser old config hid:
  `connect: (ConnectOptions) => Promise<void>` named its parameter after
  its type and silently took `any`, and the WHIP module type never
  declared `whipPeerConnectionState` even though useWhipConnectionState
  reads it.
- The iOS config plugin wrote `ios.deploymentTarget` unconditionally, so
  it downgraded the Expo template's own default (16.4 on SDK 57) to this
  SDK's 15.1 minimum and left CocoaPods unable to resolve the Expo pod.
  It now only raises an existing lower value, and honours an explicit
  `iphoneDeploymentTarget` as before. The example's app.json no longer
  pins 15.1 for the same reason.
- RN 0.86 widened `useColorScheme()` to include 'unspecified' and made it
  non-nullable, so the example's hook collapses it to the two themes it
  actually defines.

Verified: yarn build, yarn tsc, yarn lint:check, yarn docs, expo export,
expo prebuild --clean, an iOS simulator build of the Expo example and
./gradlew :app:assembleDebug for Android - all green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Type both `wh{i,e}pPeerConnectionState` as optional. Neither is backed
  by a native `Property` on either platform, so they read back as
  `undefined`, which `PeerConnectionState | null` did not allow. Neither
  is re-exported from `src/index.ts`, so this is internal to the module
  files; the connection-state hooks already fall back to "unknown".
- Floor `expo` at the version this was verified against (`^57.0.18`)
  rather than `^57.0.0`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@majkpal
majkpal force-pushed the chore/upgrade-expo-sdk-57 branch from bd66763 to 517335b Compare August 31, 2026 09:17
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@majkpal
majkpal merged commit 1a753be into software-mansion:main Aug 31, 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