Skip to content

Commit 68bbbba

Browse files
chrfalchclaude
andcommitted
feat(spm): redesign react-native spm to add/update/deinit; drop from-scratch generator
Replace the ambiguous `init`/`--from-scratch` (with its silent in-place→from-scratch fall-through that could rename a user's project to .legacy) with four clear verbs: add inject SPM into the existing .xcodeproj, in place (idempotent; fail-loud on a CocoaPods-integrated pbxproj). --deintegrate runs `pod deintegrate` + strips RN from the Podfile + removes the leftover empty Pods group. update re-run the pipeline + refresh the injection. deinit surgical inverse of add (reverse exactly what .spm-injected.json records → byte-identical revert; no prompt). scaffold unchanged. sync/codegen/download stay but are hidden from primary help. Zero-arg `npx react-native spm` auto-resolves: injected→update; a fresh CocoaPods project (safe-gate: stock Podfile + git-clean pbxproj/Podfile)→ add --deintegrate; else strict add. - Delete the from-scratch xcodeproj generator + legacy-migration/Podfile-patch machinery and the now-dead whole-file-generation helpers in spm-pbxproj.js. - Add surgical pbxproj removal primitives (removeObjectByUuid, removeArrayMembersByUuid, removeField, removeArrayStringValues, removeEmptyPodsGroup); injection now records its exact edits in .spm-injected.json so deinit can reverse them. - Merge flags: --skip/force-download → --download <auto|skip|force>; --local-xcframework + --artifacts-dir → --artifacts <path>. Remove --skip-xcodeproj/--force-xcodeproj/--bundle-identifier/--entry-file and the --platform-name CLI shim. - generate-spm-package now throws on artifact-slot failures (incl. missing ReactNativeHeaders) instead of a silent exitCode+return. - Update CLI registration, __doc__/spm-scripts.md, and the spm test suite. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent d9e0a80 commit 68bbbba

12 files changed

Lines changed: 1236 additions & 3010 deletions

packages/react-native/react-native.config.js

Lines changed: 19 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -116,105 +116,53 @@ const spmCommand /*: Command */ = {
116116
name: 'spm [action]',
117117
description:
118118
'Set up or maintain Swift Package Manager support for the iOS/macOS app. ' +
119-
'Actions: init, update, sync, clean, codegen, download, scaffold. ' +
120-
'With no action: defaults to update.',
119+
'Actions: add, update, deinit, scaffold. With no action: add (or update ' +
120+
'if SPM is already set up).',
121121
options: [
122122
{
123123
name: '--version <string>',
124124
description:
125125
'React Native version (e.g. 0.80.0). Defaults to the version in node_modules/react-native/package.json.',
126126
},
127-
{
128-
name: '--localXcframework <path>',
129-
description: 'Use a local React.xcframework instead of downloading.',
130-
},
131-
{
132-
name: '--artifactsDir <path>',
133-
description: 'Override the artifact cache directory.',
134-
},
135127
{
136128
name: '--flavor <string>',
137129
description: 'Artifact flavor: debug or release.',
138130
},
139131
{
140-
name: '--skipCodegen',
141-
description: 'Skip react-native codegen step.',
142-
},
143-
{
144-
name: '--skipDownload',
145-
description: 'Skip automatic artifact download.',
146-
},
147-
{
148-
name: '--forceDownload',
149-
description: 'Clear cached artifacts and re-download from Maven.',
150-
},
151-
{
152-
name: '--skipXcodeproj',
153-
description: 'Skip .xcodeproj generation.',
154-
},
155-
{
156-
name: '--forceXcodeproj',
157-
description:
158-
'Regenerate <App>.xcodeproj even when one already exists. ' +
159-
'Clobbers Xcode-side edits (signing, capabilities, Build Phases).',
160-
},
161-
{
162-
name: '--fromScratch',
163-
description:
164-
'[init] Generate a brand-new <App>.xcodeproj (renaming the existing ' +
165-
'one to .legacy) instead of the default in-place injection into the ' +
166-
'existing project.',
132+
name: '--yes',
133+
description: 'Skip the dirty-pbxproj confirmation prompt.',
167134
},
168135
{
169136
name: '--xcodeproj <path>',
170137
description:
171-
'[init] Path to the existing .xcodeproj to inject SPM packages into ' +
138+
'[add] Path to the .xcodeproj to inject SPM packages into ' +
172139
'(disambiguates when several exist).',
173140
},
174-
{
175-
name: '--bundleIdentifier <string>',
176-
description: 'Override CFBundleIdentifier in the generated Info.plist.',
177-
},
178141
{
179142
name: '--productName <string>',
180-
description: 'Override PRODUCT_NAME in the generated Info.plist.',
181-
},
182-
{
183-
name: '--entryFile <path>',
184143
description:
185-
'JS entry file relative to app root (default: package.json "main" or index.js).',
144+
'[add] App target to inject into (disambiguates when several exist).',
186145
},
187146
{
188-
name: '--project',
147+
name: '--deintegrate',
189148
description:
190-
'[clean] Also remove Package.swift and <App>-SPM.xcodeproj/.',
149+
'[add] Run `pod deintegrate` and strip React Native from the Podfile ' +
150+
'before injecting (CocoaPods → SwiftPM migration).',
191151
},
192152
{
193-
name: '--derivedData',
153+
name: '--artifacts <path>',
194154
description:
195-
"[clean] Also remove this app's DerivedData (~/Library/Developer/Xcode/DerivedData/<App>-SPM-*).",
155+
'[advanced] Local artifact source: a .xcframework file (used directly, ' +
156+
'no download) or a directory (cache dir to read/download into).',
196157
},
197158
{
198-
name: '--cache',
159+
name: '--download <string>',
199160
description:
200-
'[clean] Also remove the cached xcframework slot for the current resolved version.',
161+
'[advanced] Artifact download policy: auto (default), skip, or force.',
201162
},
202163
{
203-
name: '--all',
204-
description: '[clean] Shorthand for --project --derivedData --cache.',
205-
},
206-
{
207-
name: '--yes',
208-
description:
209-
'[clean] Skip the confirmation prompt for destructive scopes.',
210-
},
211-
// Workaround for @react-native-community/cli: when any positional equals
212-
// "init" (including our `spm init` action), the CLI naively appends
213-
// `--platform-name <platform>` to argv. Accept and ignore it so commander
214-
// does not reject the unknown option.
215-
{
216-
name: '--platform-name <string>',
217-
description: '(ignored — CLI compatibility shim for `spm init`)',
164+
name: '--skipCodegen',
165+
description: '[advanced] Skip the react-native codegen step.',
218166
},
219167
],
220168
func: async (argv, _config, args) => {
@@ -224,13 +172,11 @@ const spmCommand /*: Command */ = {
224172
}
225173
const stringOpts /*: Array<[string, string]> */ = [
226174
['version', '--version'],
227-
['localXcframework', '--local-xcframework'],
228-
['artifactsDir', '--artifacts-dir'],
229175
['flavor', '--flavor'],
230-
['bundleIdentifier', '--bundle-identifier'],
231176
['productName', '--product-name'],
232-
['entryFile', '--entry-file'],
233177
['xcodeproj', '--xcodeproj'],
178+
['artifacts', '--artifacts'],
179+
['download', '--download'],
234180
];
235181
for (const [key, flag] of stringOpts) {
236182
if (args[key] != null) {
@@ -239,15 +185,7 @@ const spmCommand /*: Command */ = {
239185
}
240186
const boolOpts /*: Array<[string, string]> */ = [
241187
['skipCodegen', '--skip-codegen'],
242-
['skipDownload', '--skip-download'],
243-
['forceDownload', '--force-download'],
244-
['skipXcodeproj', '--skip-xcodeproj'],
245-
['forceXcodeproj', '--force-xcodeproj'],
246-
['fromScratch', '--from-scratch'],
247-
['project', '--project'],
248-
['derivedData', '--derived-data'],
249-
['cache', '--cache'],
250-
['all', '--all'],
188+
['deintegrate', '--deintegrate'],
251189
['yes', '--yes'],
252190
];
253191
for (const [key, flag] of boolOpts) {

0 commit comments

Comments
 (0)