Skip to content

Commit c7e3497

Browse files
chrfalchclaude
andcommitted
Document spm.dependencies and the scaffold prerequisite
Summary: Two things implemented in the code and absent from the docs. **`spm.dependencies`.** The SwiftPM analog of a podspec's `s.dependency` — how a library declares it needs another native library — is implemented in `expand-spm-dependencies.js` and was documented in no doc at all, so a library author porting a podspec had no way to find the mechanism replacing `s.dependency`. Added a section next to the other `react-native.config.js` surfaces, noting it resolves recursively and is a library-author surface rather than an app one. **The scaffold prerequisite.** "Community packages without a `Package.swift`" said the *build* fails. It is `spm add`/`update` that stops, during autolinking generation, with exit code **2** — deliberately distinct so the Xcode sync hook can treat it as a hard build error while staying lenient about transient sync failures. Neither the exit code nor the reason `add`/`update` refuse to auto-scaffold (it would hide a real gap in the dependency's SPM support) was written down. Also noted that `scaffold` runs codegen and autolinking but does *not* inject, so a first-time setup still needs the follow-up `npx react-native spm`, and added a troubleshooting row keyed on the error text since that is what people will search for. Changelog: [Internal] Test Plan: Traced to `expand-spm-dependencies.js` for the recursive expansion, and to `reportMissingManifests` in `generate-spm-autolinking.js` plus its handling in `setup-apple-spm.js`, where the `scaffold` action runs before the shared codegen/autolinking steps and injection stays gated on `action === 'add'`. Prettier clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent ebac880 commit c7e3497

1 file changed

Lines changed: 38 additions & 3 deletions

File tree

‎packages/react-native/scripts/spm/__docs__/spm-scripts.md‎

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,29 @@ Each entry becomes a target in `build/generated/autolinking/Package.swift`.
353353
Sources outside `build/generated/autolinking/` are automatically mirrored with
354354
file-level symlinks.
355355

356+
## Dependencies between libraries
357+
358+
SwiftPM has no equivalent of a podspec's `s.dependency`, so a library that needs
359+
another native library declares it explicitly with `spm.dependencies` in its
360+
**own** `react-native.config.js` — a list of npm names:
361+
362+
```js
363+
// react-native-reanimated/react-native.config.js
364+
module.exports = {
365+
dependency: {platforms: {ios: {}}},
366+
spm: {dependencies: ['react-native-worklets']},
367+
};
368+
```
369+
370+
The autolinker starts from the directly-autolinked deps, follows each one's
371+
`spm.dependencies` **recursively**, and dedupes the result, so a transitive
372+
dependency is pulled into the package graph even when the app never depends on
373+
it directly. Declared names are mapped to Swift target names, so the dependent
374+
library's target can import it.
375+
376+
This is a **library-author** surface, like the podspec dependency it replaces —
377+
apps don't normally set it.
378+
356379
## Self-managed community packages
357380

358381
A community library that ships its own `Package.swift` is referenced directly by
@@ -370,14 +393,25 @@ build.
370393

371394
## Community packages without a Package.swift
372395

373-
If an autolinked library ships **no `Package.swift`**, the build fails with a
374-
clear per-dep error (`Package.swift is missing for library "<name>"`). Generate
375-
one from the library's podspec:
396+
If an autolinked library ships **no `Package.swift`**, `spm add`/`update` stops
397+
with a per-dep error (`Package.swift is missing for library "<name>"`) and exits
398+
**2** — a distinct code from a generic failure, so CI and the Xcode sync hooks
399+
can treat it as a hard error while staying lenient about transient sync
400+
failures.
401+
402+
`add` and `update` deliberately **never** scaffold on your behalf:
403+
auto-scaffolding would hide a real gap in the dependency's SPM support. Generate
404+
the manifest from the library's podspec explicitly, then re-run setup:
376405

377406
```bash
378407
npx react-native spm scaffold # writes Package.swift into node_modules/<dep>/
408+
npx react-native spm # then inject/update as usual
379409
```
380410

411+
(`scaffold` also runs codegen and regenerates the autolinking package, but it
412+
does not inject into the `.xcodeproj` — so on a first-time setup you still
413+
follow it with `npx react-native spm`.)
414+
381415
Because `node_modules/` isn't committed, persist it so it survives the next
382416
install:
383417

@@ -440,6 +474,7 @@ across apps; refresh it with `react-native spm update --download force`.
440474
| `spm add` fails: "CocoaPods-integrated project" | Re-run `spm add --deintegrate` (runs `pod deintegrate` + strips RN from the Podfile), or `pod deintegrate` yourself first. |
441475
| `spm add` fails: "no .xcodeproj found" | Create an app first (`npx @react-native-community/cli init`) or make a project in Xcode, then `spm add`. |
442476
| `spm add` fails: "multiple .xcodeproj found" | Pass `--xcodeproj <path>` (and `--product-name <target>` if multiple app targets). |
477+
| `Package.swift is missing for library "<name>"` (exit 2) | The dep ships no SwiftPM support. `npx react-native spm scaffold`, then re-run setup; persist with `patch-package`. See [Community packages without a Package.swift](#community-packages-without-a-packageswift) |
443478
| Missing headers | Re-run `react-native spm` |
444479
| "not contained in target" | Re-run setup (regenerates file-level symlinks) |
445480
| Codegen fails | Use `--skipCodegen` to iterate on other parts |

0 commit comments

Comments
 (0)