2 Commits
Author SHA1 Message Date
Christian Falch 1cfc5f29a0 Derive an SPM library's Swift name from its podspec (#58290)
Summary:
An autolinked library's SwiftPM target name is also its header import prefix, so deriving it from the npm package name was wrong for most of the ecosystem (`react-native-svg` publishes `RNSVG`, not `ReactNativeSvg`) and wrong silently — no error, just headers nobody can import under the expected name.

## How:

This PR reads the podspec file on scaffolding, and will use the name from the podspec if available. In addition it deprecates the react-native.config.js `spm` section in favor of the library's `package.json` file.

### Configuration

A package's SwiftPM settings now live in `swiftpmConfig` in its `package.json`, following `codegenConfig`'s conventions: `name`, `dependencies`, `autolinkingPlugin` and `scaffold` for a library, `modules` and `denyPlugins` for an app. The `spm` block in react-native.config.js is deprecated — still read, so nothing breaks, but it warns once per file and package.json wins field by field.

### Resolving

A name resolves from `swiftpmConfig.name`, then the deprecated `spm.name`, then the podspec's `header_dir` or name, then the npm name. The podspec is thereby transitional rather than permanent: `spm scaffold` records the name it derived as `swiftpmConfig.name` in the library's package.json, so the next run needs no podspec to name it. It never overwrites a name the library already declares, never records a name guessed from the npm name, and reports what it did.

### Failsafety

A prefix Swift cannot spell is normalized to the identifier SwiftPM would compile it as, with a warning. A reserved name or two deps landing on one name is a hard error naming swiftpmConfig.name as the fix; the scope-borrowing that auto-corrected collisions is removed, since a name the build invents is a name no #import can predict. Collision checks key on SwiftPM's c99 name, so react-native-svg and react_native_svg no longer pass and then compile as one module.

### Implementation

Name resolution reads the two podspec fields it needs with the regex parser, so it adds no `pod ipc spec` spawn, and the full read is memoized on the resolved path so one run reads a podspec once across name resolution, header search paths and scaffolding.

`rn-tester` and the Apple test library move to the new location.

## Changelog:

[IOS] [FIXED] - Read SwiftPM name from podspec and store in package.json when scaffolding

Pull Request resolved: https://github.com/react/react-native/pull/58290

Test Plan: ✅ Unit tests

Reviewed By: cortinico

Differential Revision: D119159904

Pulled By: cipolleschi

fbshipit-source-id: 59a7c62ecb601498060a5721f362dae8c5cc92de
2026-09-09 10:22:46 -07:00
Christian Falch 47fad096a4 feat(iOS) swiftpm support in iOS (#57332)
Summary:
⚠️  This is a stacked PR — review/merge the base PRs first

Builds on, and should land after (bottom-up):

1. https://github.com/react/react-native/issues/57285 — Remove the Clang VFS overlay / modularize React headers (base of the stack). <React/…> via the framework module map; lowercase namespaces (react/, yoga/, jsi/, …) via the ReactNativeHeaders module map.
2. https://github.com/react/react-native/issues/57305 — Prebuilt artifact resources + ReactNativeHeaders.xcframework. Ships the prebuilt core artifacts (incl. ReactNativeHeaders in the tarball + embedded React.framework resources) and the CocoaPods React-Core-prebuilt facades.
3. https://github.com/react/react-native/issues/57440 — Self-serving prebuilt ReactNativeDependencies + dependency-only facades. The deps pod becomes the single header authority for the third-party namespaces (RCT-Folly/glog/boost/…); community `s.dependency "RCT-Folly"` resolves to local facades instead of trunk source pods.
4. https://github.com/react/react-native/issues/57442 — ReactNativeDependenciesHeaders sidecar + pure-RN ReactNativeHeaders (immediate base). The deps prebuild emits a headers-only LIBRARY-type sidecar (the binary deps xcframework is framework-type — invisible to SwiftPM binaryTargets), ReactNativeHeaders drops the third-party namespaces, and both headers artifacts publish standalone to Maven.

The whole stack is rebased onto current main (2026-07-06).

This PR consumes the final **five-artifact set**: React, ReactNativeHeaders (pure-RN), ReactNativeDependencies, ReactNativeDependenciesHeaders, hermes-engine.

Adds npx react-native spm and the package-generation tooling that turns an app into a SwiftPM-integrated RN app using the base stack's prebuilt XCFrameworks. CocoaPods stays supported — additive, opt-in, no Ruby toolchain. Integration is injected into the existing .xcodeproj in place (nothing generated/renamed/replaced), recorded in .spm-injected.json so it reverses exactly.

### What this PR adds

- The spm CLI (add/update/deinit/scaffold + hidden sync/codegen/download), zero-arg auto-resolution, --deintegrate for CocoaPods→SwiftPM.
- SwiftPM package generation (scripts/spm/): autolinking→Package.swift, Codegen→React-GeneratedCode, core XCFramework binary targets, artifact download/cache, surgical pbxproj inject/remove.
- ReactNativeDependenciesHeaders wired as the 5th binaryTarget: the headers-only companions (ReactNativeHeaders from the core tarball, the deps sidecar from the deps tarball) are staged automatically out of their parent tarballs — no --headers-tarball priming; REQUIRED_ARTIFACTS covers all five.
- Community-library scaffolding from podspecs (incl. root-level-source podspecs via generated include/<SwiftName>/ shims, sibling wiring for transitive spm.dependencies, self-ingestion guards).
- In-place Xcode integration (XCLocalSwiftPackageReference + Sync build phase + scheme pre-action + auto-sync; ${PODS_ROOT}-anchored REACT_NATIVE_PATH replaced on --deintegrate with exact deinit rollback).
- rn-tester + helloworld SwiftPM consumption + test library; npm-packaging hygiene; a small RNCoreFacades.podspec_dir fix.

## Documentation

- **Tool docs** (usage, quick start, architecture): [`scripts/spm/__doc__/spm-scripts.md`](https://github.com/react/react-native/blob/chrfalch/swift-package-manager/packages/react-native/scripts/spm/__doc__/spm-scripts.md)
- **Header-paths contract** (how the five artifacts serve headers): [`scripts/spm/__doc__/spm-header-paths-contract.md`](https://github.com/react/react-native/blob/chrfalch/swift-package-manager/packages/react-native/scripts/spm/__doc__/spm-header-paths-contract.md)
- **RFC** (updated): [react-native-community/discussions-and-proposals#994](https://github.com/react-native-community/discussions-and-proposals/pull/994)

## Changelog:

[IOS] [ADDED] - `npx react-native spm` command + SwiftPM package-generation tooling (opt-in; CocoaPods stays supported)

Pull Request resolved: https://github.com/react/react-native/pull/57332

Test Plan:
350 scripts/spm unit tests (incl. byte-identical add→deinit round-trip); manual E2E against the five-artifact set: fresh app via `cli init`→`spm add --deintegrate`→build (artifact resources verified in the app), rn-tester in-place migration (RNTesterPods.xcodeproj, test libraries + spmModules), helloworld in-place migration — all BUILD SUCCEEDED. Verified `npx react-native spm <cmd>` from the command line in each journey.

## Scope & limitations

iOS, prebuilt-only (no build-from-source yet); full spm.xcframework/spm.source library metadata not yet (app-local spm.modules + scaffolding are); Expo not yet.

## Follow-ups

Remote-mode ReactNative Package.swift must vend the ReactNativeDependenciesHeaders product (spm-distribution repo); library self-containment for repo-portable manifests; build-from-source.

Reviewed By: mdvacca

Differential Revision: D111449548

Pulled By: cipolleschi

fbshipit-source-id: 87a873bf5c8be2d60f7893611e16924bfa730a46
2026-07-15 05:08:52 -07:00