Summary
Migrating an Expo (CNG / expo prebuild) project into Rock via npm create rock produces a syntactically broken ios/Podfile that breaks every subsequent build, both via Rock and via direct pod install.
What happens
After running npm create rock in an Expo project with a prebuilt ios/, line 42 of ios/Podfile becomes:
config = use_native_modules!(['npx', 'rock', 'config', '-p', 'ios'])(config_command)
This is two consecutive call expressions with no operator between them — Ruby parser refuses it:
[!] Invalid `Podfile` file: syntax error found
42 | ... (config_command)
| ^ unexpected '(', expecting end-of-input
Every subsequent rock run:ios (and a manual pod install) then fails:
■ Failed: Installing CocoaPods dependencies
■ RockError: CocoaPods installation failed.
Root cause
packages/create-app/src/lib/utils/initInExistingProject.ts, function updatePodfile:
const replaced = content.replace(
/(config\s*=\s*use_native_modules!)(\s*)/g,
"$1(['npx', 'rock', 'config', '-p', 'ios'])$2",
);
The regex matches config = use_native_modules! plus any whitespace after the ! — it does not consume an existing argument list.
- Community-CLI template Podfile:
config = use_native_modules! (no argument) → regex inserts Rock's argument, result is well-formed. Works.
- Expo prebuild template Podfile:
config = use_native_modules!(config_command) (Expo passes its own autolinking command in as an argument) → regex matches only the prefix config = use_native_modules!, inserts (['npx', 'rock', 'config', '-p', 'ios']) right before the existing (config_command), leaving the latter on the line as a leftover. Broken Ruby.
Steps to reproduce
- Any Expo project with
ios/ generated by expo prebuild (SDK 55 here, but the Expo template has shipped use_native_modules!(config_command) for a long time).
npm create rock (selects iOS platform).
- Open
ios/Podfile → broken line 42.
pnpm rock run:ios (or pod install directly) → fails with the syntax error above.
Suggested fix
Make the regex consume the existing argument tuple so it gets replaced in full:
const replaced = content.replace(
/(config\s*=\s*use_native_modules!)(\s*\([^)]*\))?/g,
"$1(['npx', 'rock', 'config', '-p', 'ios'])",
);
The optional group (\s*\([^)]*\))? matches an existing parenthesized argument list (Expo's case) and lets it be replaced; on Community-CLI Podfiles it matches nothing, behaviour is unchanged.
The trailing-whitespace capture ($2 in the old regex) is not actually needed — whitespace before the next token survives because the regex doesn't consume it.
Why this matters
The Rock README points existing Community-CLI teams at npm create rock as the migration path. Expo (CNG) is currently the recommended starting point for new React Native projects, and many existing teams have already migrated to it. For those teams the migrator silently produces a broken Podfile that they then have to manually unbreak (and re-fix on every expo prebuild --clean, because ios/ is regenerated and gitignored).
A one-character regex change makes npm create rock Just Work on Expo projects too.
Environment
- Rock: 0.13.0
- Expo: SDK 55.0.23
- React Native: 0.83.6
- pnpm: 10.30.0
- Node: 22.14.0
- macOS, Apple Silicon
Summary
Migrating an Expo (CNG /
expo prebuild) project into Rock vianpm create rockproduces a syntactically brokenios/Podfilethat breaks every subsequent build, both via Rock and via directpod install.What happens
After running
npm create rockin an Expo project with a prebuiltios/, line 42 ofios/Podfilebecomes:This is two consecutive call expressions with no operator between them — Ruby parser refuses it:
Every subsequent
rock run:ios(and a manualpod install) then fails:Root cause
packages/create-app/src/lib/utils/initInExistingProject.ts, functionupdatePodfile:The regex matches
config = use_native_modules!plus any whitespace after the!— it does not consume an existing argument list.config = use_native_modules!(no argument) → regex inserts Rock's argument, result is well-formed. Works.config = use_native_modules!(config_command)(Expo passes its own autolinking command in as an argument) → regex matches only the prefixconfig = use_native_modules!, inserts(['npx', 'rock', 'config', '-p', 'ios'])right before the existing(config_command), leaving the latter on the line as a leftover. Broken Ruby.Steps to reproduce
ios/generated byexpo prebuild(SDK 55 here, but the Expo template has shippeduse_native_modules!(config_command)for a long time).npm create rock(selects iOS platform).ios/Podfile→ broken line 42.pnpm rock run:ios(orpod installdirectly) → fails with the syntax error above.Suggested fix
Make the regex consume the existing argument tuple so it gets replaced in full:
The optional group
(\s*\([^)]*\))?matches an existing parenthesized argument list (Expo's case) and lets it be replaced; on Community-CLI Podfiles it matches nothing, behaviour is unchanged.The trailing-whitespace capture (
$2in the old regex) is not actually needed — whitespace before the next token survives because the regex doesn't consume it.Why this matters
The Rock README points existing Community-CLI teams at
npm create rockas the migration path. Expo (CNG) is currently the recommended starting point for new React Native projects, and many existing teams have already migrated to it. For those teams the migrator silently produces a broken Podfile that they then have to manually unbreak (and re-fix on everyexpo prebuild --clean, becauseios/is regenerated and gitignored).A one-character regex change makes
npm create rockJust Work on Expo projects too.Environment