Skip to content

chore(v6): upgrade to Expo SDK 56#4944

Open
azizbecha wants to merge 10 commits into
callstack:v6from
azizbecha:@azizbecha/chore/expo-sdk-56
Open

chore(v6): upgrade to Expo SDK 56#4944
azizbecha wants to merge 10 commits into
callstack:v6from
azizbecha:@azizbecha/chore/expo-sdk-56

Conversation

@azizbecha
Copy link
Copy Markdown
Collaborator

Motivation

  • Example: Expo ~56.0.0-preview.10, RN 0.85.3, React 19.2.3, expo-* aligned via expo install --fix.
  • Core devDeps aligned to match; added @react-native/jest-preset (extracted from RN in 0.85).
  • Deleted example/android / example/ios, gitignored. expo run:* regenerates them via prebuild.
  • Dropped @expo/webpack-config; web served by Metro (config aliases for vector icons + crypto preserved).
  • app.json cleanup (deprecated privacy/packagerOpts/splash/newArchEnabled removed, splash moved into the plugin). expo-doctor 18/18.
  • Fixed deprecations surfaced by RN 0.85 / React 19.2:
    • absoluteFillObjectabsoluteFill
    • Image style.tintColor/resizeMode → props
    • shadow*boxShadow (token still sourced from Palette.primary0)
  • Fixed React 19.2 hydration error in CustomFABControls (nested <button>).
  • Fixed pre-existing typo in DrawerItems (Dynamic Theme row used a JS comma expression instead of a style array).

Test plan

  • yarn typescript, yarn lint, yarn test all green (55 suites / 726 tests / 161 snapshots).
  • cd example && npx expo-doctor → 18/18 ✓.
  • cd example && yarn ios, yarn android, yarn web all boot.
  • All components render correctly on all platforms.

azizbecha added 10 commits May 13, 2026 17:45
Example app:
- expo ^56.0.0-preview.10
- react/react-dom 19.2.3, react-native 0.85.3
- expo-* aligned via 'npx expo install --fix'
- react-native-reanimated 4.3.1, react-native-worklets 0.8.3
- react-native-gesture-handler ~2.31.1, safe-area-context ~5.7.0
- react-native-screens 4.25.0
- babel-preset-expo ~56.0.0, @babel/core ^7.29.0
- app.json: add expo-splash-screen config plugin (now required)

Core (root devDependencies):
- react/react-dom 19.2.3, react-native 0.85.3, react-test-renderer 19.2.3
- @react-native/babel-preset ^0.85.3
- react-native-safe-area-context 5.7.0
- @babel/core ^7.29.0, @babel/runtime ^7.29.0
- add @react-native/jest-preset ^0.85.3 (RN 0.85 moved jest-preset to
  a separate package) and point jest.preset at it

Other fixes required by the new typedefs:
- replace removed StyleSheet.absoluteFillObject with StyleSheet.absoluteFill
  in Modal and TouchableRipple.native
- TeamDetails example: handle 'unspecified' from useColorScheme

v6 needs the newer react-native-reanimated bundled with SDK 56, and v6 is
not shipping imminently, so the SDK 56 preview is acceptable.
Delete example/android/ and example/ios/ so Expo Continuous Native
Generation regenerates them from app.json + config plugins at build
time. The committed Android project was stale at SDK 52 and was the
reason runtimeVersion was pinned to exposdk:52.0.0.

example/ios/ was not tracked in git.

Update example scripts to use --dev-client (Expo Go does not support
the dev-client-only modules and we'll use development builds going
forward).
@expo/webpack-config has been deprecated since Expo SDK 50; Metro is
the supported web bundler going forward.

example/package.json
- remove @expo/webpack-config, file-loader, url-loader, typeface-roboto

example/webpack.config.js — deleted

example/metro.config.js
- port the web-only aliases from the old webpack config via
  resolver.resolveRequest:
  - @react-native-vector-icons/material-design-icons -> @expo/vector-icons
  - crypto -> expo-crypto

example/index.web.js
- call registerRootComponent so Metro web actually mounts the app
  (webpack used to bootstrap this implicitly)

example/public/index.html
- remove the static <script src="app.bundle.js"> tag (Metro injects
  its own bundle URL)
- load Roboto from Google Fonts CDN

example/assets/styles/fonts.css
- map the legacy 'Roboto-<Weight>' family names to the CDN-loaded
  Roboto via local() so the existing app code keeps working
- runtimeVersion: switch from the hardcoded 'exposdk:52.0.0' (which was
  pinned to the deleted Android project) to { policy: 'sdkVersion' } so
  EAS Update tracks the installed SDK automatically.
- newArchEnabled: removed; new architecture has been the default since
  Expo SDK 53.
app.json
- remove deprecated fields: privacy, packagerOpts, splash
- migrate splash settings into the expo-splash-screen plugin entry

metro.config.js
- inline monorepo setup (drop react-native-monorepo-config); append
  to Expo's default watchFolders instead of replacing them, which fixes
  the expo-doctor "watchFolders does not contain all entries from
  Expo's defaults" check
- use the canonical 'expo/metro-config' entry

package.json
- remove react-native-monorepo-config (no longer needed)

expo-doctor: 18/18 checks pass.
Once we delete the committed ios/android folders and rely on
'expo run:*' to prebuild them locally, EAS Update treats the resulting
build as bare-workflow and rejects policy-style runtimeVersion values
at startup ("You're currently using the bare workflow, where runtime
version policies are not supported"). Set it to the literal "56.0.0"
to match the installed SDK.

Also add the CNG-generated /android and /ios paths to .gitignore so
they're not accidentally committed, which also clears the related
expo-doctor warning about app.json fields not being synced when
native folders are present.
The outer TouchableOpacity (from react-native-gesture-handler) rendered
a <button> on web because of accessibilityRole='button'. Inside it,
Paper's RadioButton also renders a <button>. Under React 19.2 this
turns from a tolerated warning into a hard hydration error
("<button> cannot contain a nested <button>").

Drop the redundant accessibilityRole on the outer TouchableOpacity;
its Pressable semantics are enough and RadioButton remains the
announced button.
shadow*/shadowOpacity/shadowOffset/shadowRadius style props are
deprecated in React Native 0.85. Return a single boxShadow entry
instead.

- Static case: { offsetX, offsetY, blurRadius, color } with the alpha
  baked into color (boxShadow has no separate opacity field).
- Animated case: same shape, but offsetY / blurRadius / color are
  driven by the same elevation Animated.Value, so the elevation
  transition is preserved.

Shadow color still comes from the MD3 Palette.primary0 token; the
alpha is applied via the 'color' library to keep the token convention.
React Native deprecates the style-form of these properties on Image:
"Image: style.resizeMode is deprecated. Please use props.resizeMode."
"Image: style.tintColor is deprecated. Please use props.tintColor."

- Icon (image source variant): tintColor / resizeMode lifted out of the
  style array onto the <Image> props.
- AppbarBackIcon (iOS back chevron): same migration; drop the now-empty
  styles.icon entry.

Snapshot in Appbar.test.tsx updated to reflect the new prop placement.
The Use Dynamic Theme row in the Preferences drawer section had
style={(styles.preference, styles.v3Preference)} — a JS comma
expression that evaluates to only styles.v3Preference. That dropped
the row's flexDirection: 'row' / justifyContent: 'space-between'
layout, so the trailing Switch overflowed the drawer on Android.

Match the array form used by every other preference row:
style={[styles.preference, styles.v3Preference]}.
@callstack-bot
Copy link
Copy Markdown

Hey @azizbecha, thank you for your pull request 🤗. The documentation from this branch can be viewed here.

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