Repository navigation
Mark SwiftPM remote-package mode as planned in the docs #59631
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c3fee66
b32bad9
c0e4b96
7cd0824
9ad602d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -59,11 +59,15 @@ walk-up, no JSON, no `import Foundation`. | |
| | ------------------------ | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | ||
| | Autolinked aggregator | `build/generated/autolinking/Package.swift` | Neither: it has no inline targets, and references only its dependencies' packages (`packages/<Name>`, `libs/<Name>`, plugin packages) | | ||
| | Local-module wrapper | `build/generated/autolinking/packages/<Name>/` | `.package(path: "../../../../xcframeworks")` + `"../../../ios"` (only for `swiftpmConfig.modules` entries) | | ||
| | Codegen template | `build/generated/ios/Package.swift` | `.package(path: "../../xcframeworks")` (or the remote url) | | ||
| | App target (pbxproj) | `<App>.xcodeproj` | local `XCLocalSwiftPackageReference` (or `XCRemoteSwiftPackageReference` in remote mode) | | ||
| | Scaffolded community lib | `node_modules/<dep>/Package.swift` | scaffold-time relative paths to the app's xcframeworks + codegen packages (or `.package(url:exact:)` in remote mode) | | ||
| | Codegen template | `build/generated/ios/Package.swift` | `.package(path: "../../xcframeworks")` | | ||
| | App target (pbxproj) | `<App>.xcodeproj` | local `XCLocalSwiftPackageReference` | | ||
| | Scaffolded community lib | `node_modules/<dep>/Package.swift` | scaffold-time relative paths to the app's xcframeworks + codegen packages | | ||
|
|
||
| ## Remote-package mode | ||
| ## Remote-package mode (planned) | ||
|
|
||
| > **Planned, not supported.** The `RN_SPM_REMOTE_URL` code path exists, but it | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The docs say not to use remote mode, but
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. As promised in the last round, the runtime warning comes in a separate PR. It will also stop pointing users at |
||
| > is unsupported. Do not use it. Libraries and apps do not need a remote form. | ||
| > The text below records the design intent. | ||
|
|
||
| A **URL alone** turns remote mode on: `RN_SPM_REMOTE_URL`, or the persisted | ||
| `url`. The whole app graph then uses a single remote React Native package | ||
|
|
@@ -106,26 +110,62 @@ tooling never silently pins an unpublished tag. | |
| ## Hand-authored community library contract | ||
|
|
||
| The tooling leaves untouched a library that ships its own `Package.swift` (no | ||
| scaffolder or autolinker marker). That library needs only two things, and **no | ||
| discovery code**: | ||
|
|
||
| 1. Depend on the React Native SPM package and its products — in remote mode | ||
| `.package(url: "<repo>", exact: "<version>")` + | ||
| `.product(name: "ReactHeaders", package: "<identity>")`, | ||
| `.product(name: "ReactNativeHeaders", package: "<identity>")`, and | ||
| `.product(name: "ReactNativeDependenciesHeaders", package: "<identity>")`, | ||
| where `<identity>` is the URL tail, lowercased, without `.git`. A scaffolded | ||
| manifest depends on the same React Native products. Libraries should declare | ||
| a version RANGE in production; the consuming app pins EXACT. | ||
| 2. Ship its own generated code: set `codegenConfig.includesGeneratedCode: true` | ||
| and generate with | ||
| scaffolder or autolinker marker). That library needs two things, and **no | ||
| discovery code**. A third thing is optional: | ||
|
|
||
| 1. Depend on the React Native package and the app's codegen package by relative | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Worth noting that
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added: libraries that depend on |
||
| path. SwiftPM reaches the library's manifest through React Native's | ||
| per-library link folder, `build/generated/autolinking/libs/<SwiftName>`, | ||
| named after the library's Swift name, not its npm name. The paths are | ||
| relative to that folder: | ||
| `.package(name: "ReactNative", path: "../../../../xcframeworks")` and | ||
| `.package(name: "React-GeneratedCode", path: "../../../ios")`. The target | ||
| then depends on `.product(name: "ReactHeaders", package: "ReactNative")`, | ||
| `.product(name: "ReactNativeHeaders", package: "ReactNative")`, | ||
| `.product(name: "ReactNativeDependenciesHeaders", package: "ReactNative")`, | ||
| and `.product(name: "ReactAppHeaders", package: "React-GeneratedCode")`. A | ||
| scaffolded manifest depends on the same products. `React-GeneratedCode` | ||
| declares `.iOS(.v15)`, so the library must declare `.iOS(.v15)` or higher. | ||
| 2. Set the React Native defines on each target. SwiftPM mode supports only the | ||
| New Architecture, and nothing sets `RCT_NEW_ARCH_ENABLED` for a hand-authored | ||
| manifest. Without it, the preprocessor drops all code behind | ||
| `#ifdef RCT_NEW_ARCH_ENABLED`. Keep those `#ifdef` gates in the sources: the | ||
| same sources still build under CocoaPods. C++ and Objective-C++ sources also | ||
| need the config-gated `DEBUG` and `NDEBUG` defines that React Native's own | ||
| targets get. Without `NDEBUG` in Release, the `DebugStringConvertible` vtable | ||
| and the `ShadowNode` layout differ from the prebuilt React framework, and the | ||
| link fails. A library with Swift sources sets the define in `swiftSettings` | ||
| too, as CocoaPods does through `OTHER_SWIFT_FLAGS`: | ||
|
|
||
| ```swift | ||
| cSettings: [.define("RCT_NEW_ARCH_ENABLED", to: "1")], | ||
| cxxSettings: [ | ||
| .define("RCT_NEW_ARCH_ENABLED", to: "1"), | ||
| .define("DEBUG", .when(configuration: .debug)), | ||
| .define("NDEBUG", .when(configuration: .release)), | ||
| ], | ||
| swiftSettings: [.define("RCT_NEW_ARCH_ENABLED")], | ||
| ``` | ||
|
|
||
| 3. Optionally, ship its own generated code. Set | ||
| `codegenConfig.includesGeneratedCode: true` and generate with | ||
| `generate-codegen-artifacts.js --path . --targetPlatform ios --source library`. | ||
| The output lands at `<outputDir>/build/generated/ios/ReactCodegen/`. The | ||
| manifest reaches it with one safe `.headerSearchPath(...)` into the library's | ||
| own tree. The app-side codegen then skips the library's spec, so there are no | ||
| duplicate symbols. | ||
|
|
||
| The library is then self-contained. It carries no app-layout knowledge and needs | ||
| no per-app codegen headers from the consuming app. | ||
| `@chrfalch/react-native-calculator` (a hand-authored Fabric/TurboModule library) | ||
| proves this. | ||
| This is how a hand-authored library links today. The folders these relative | ||
| paths reach, `build/xcframeworks` and `build/generated/ios` under the app's | ||
| `ios/` folder, are generated output: `spm` recreates them on each machine, and | ||
| they are gitignored. The paths resolve only when SwiftPM reaches the library | ||
| through its `libs/<SwiftName>` link folder, so the library cannot build on its | ||
| own (for example, `swift build` in its own repository). The relative paths | ||
| `../../../ios` and `../../../../xcframeworks` assume the default layout. Two | ||
| options of `generate-spm-autolinking.js` change it: `--output` moves the link | ||
| folder, and `--xcframeworks-path` moves the React Native package. With either | ||
| option set, the hardcoded paths do not resolve. | ||
|
|
||
| The normal pattern is rules 1 and 2 alone: the library uses the app's generated | ||
| code from `React-GeneratedCode`. A library that takes rule 3 carries its own | ||
| generated code instead. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not for this PR, but since
RN_SPM_REMOTE_URLis now "do not use", should the code print a warning when it's set? Today it's still honored without any message.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, a warning makes sense. I will do it in a separate follow-up PR, so this one stays docs-only.