Repository navigation
fix: support Expo modules in React Native CLI apps - #487
Open
KisaneNeko wants to merge 10 commits into
Open
KisaneNeko wants to merge 10 commits into
KisaneNeko wants to merge 10 commits into
Conversation
The CLI ran `expo prebuild` whenever it found Expo and an app.json. In a React Native CLI app that installed Expo modules, prebuild regenerated the committed android/ and ios/ directories and deleted the brownfield library module, so packaging failed. Only run prebuild when the native directory is missing or gitignored (CNG). Also document the manual iOS step for these apps: Expo modules only register through the Expo host runtime, which the config plugin enables in Expo apps.
…Expo Expo modules only register through the Expo host runtime, which the config plugin enables in Expo apps. create-react-native-brownfield now does the same when the app's package.json depends on expo: the Podfile framework target gets the Expo host env and the EXPO_SDK_GTE_55 define, and the framework interface gets ensureExpoModulesProvider(). Re-running it after adding Expo switches an existing framework target over. Only the app's own package.json counts, so a hoisted expo in a monorepo does not turn the Expo host on. The Podfile hook no longer assumes Expo's podfile_properties exists.
Three things broke packaging with precompiled Expo modules outside Expo apps:
- `--use-prebuilt-expo` only picked which XCFrameworks to copy. It never told
CocoaPods to use precompiled modules, which only Expo-generated Podfiles turn
on, so a bare app failed with "XCFramework not found". The CLI now sets
EXPO_USE_PRECOMPILED_MODULES from the flag.
- Older React Native versions wrote SWIFT_ENABLE_EXPLICIT_MODULES = NO into app
projects. With precompiled Expo the React Native pods are static libraries,
and with explicit modules off Xcode can't find their module maps when it
verifies the framework's Swift interface ("cannot load underlying module").
The CLI turns explicit modules on for these builds.
- Expo's precompiled modules are built against the React Native version the SDK
targets, and crash at runtime on another minor version. The CLI now defaults
to building Expo from source in that case and warns if it's forced.
KisaneNeko
marked this pull request as ready for review
October 13, 2026 14:57
With precompiled Expo, CocoaPods symlinks expo-image's dependency XCFrameworks into node_modules. The package step copied the links, so the output broke when moved to another machine, and stripping signatures modified the files in node_modules.
- warn when git can't tell whether the native dir is gitignored - make the Expo host Podfile edit handle CRLF, comments and fail loudly - respect Podfile.properties.json and an exported opt-out for precompiled Expo - keep a user-provided SWIFT_ENABLE_EXPLICIT_MODULES value - add tests for the new defaults
CocoaPods renames the framework target's Sources phase comment to "Sources", so the idempotency check missed it and a re-run added a second phase, which broke the next pod install.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Expo modules didn't work in bare RN apps packaged with brownfield. Issues found and fixed:
expo prebuildwiped the brownfield module. The CLI ran prebuild for any project with Expo and anapp.json, which regenerated the committedandroid/andios/dirs without the library module. It now skips prebuild when the native dir is committed.create-react-native-brownfieldnow sets it up when the app depends onexpo, also when re-run after adding Expo.--use-prebuilt-expodidn't work in bare apps. It never setEXPO_USE_PRECOMPILED_MODULES, sopod installbuilt Expo from source and packaging failed with "XCFramework not found". The CLI now sets it from the flag, and without the flag it respects an exportedEXPO_USE_PRECOMPILED_MODULES=0orPodfile.properties.jsonturning it off.SWIFT_ENABLE_EXPLICIT_MODULES = NOthat RN'spod installwrites into the project. The CLI now passesSWIFT_ENABLE_EXPLICIT_MODULES=YESfor these builds.node_modules, and the CLI copied the links instead of the files. The package broke when moved off the build machine (e.g. committed to the host app's repo), and stripping signatures edited files innode_modules. Found while testing this, present since Expo 56 support (feat: add Expo 56 support #360). The CLI now copies the real files.pod installbroke the nextpod install. CocoaPods renames the framework's Sources phase, so the duplicate check missed it and added a second one ("no parent for object BrownfieldLib.swift"). This was on main already, but our docs now tell users to re-run the command after adding Expo. The check now matches any Sources phase on the target.Docs: a new guide, Expo Modules in React Native CLI Apps, with the steps for these apps. The RN CLI setup guide and the iOS guide link to it, so apps without Expo can skip it.
Behavior change
Prebuild used to run for every Expo project. Now it only runs when
ios/orandroid/is missing or gitignored. Two cases get no automatic prebuild anymore:npx expo prebuildthemselves after changingapp.jsonor plugins..git) with native dirs already present.Nothing fails in either case, but the package is built from native dirs that weren't regenerated. If that's a concern, we could add a flag to force prebuild. Happy to add it if you think committed CNG dirs are common.
Testing
node_modules/expo-imagehidden, still builds and runs.strip-framework-binary.test.tsfails onmaintoo).🤖 Generated with Claude Code