Skip to content

test(🍏): minimal SwiftPM example app and CI job - #4044

Open
chrfalch wants to merge 3 commits into
Shopify:mainfrom
chrfalch:spm-support-example
Open

test(🍏): minimal SwiftPM example app and CI job#4044
chrfalch wants to merge 3 commits into
Shopify:mainfrom
chrfalch:spm-support-example

Conversation

@chrfalch

@chrfalch chrfalch commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Motivation

Stacked on #4043, which adds packages/skia/Package.swift. Nothing exercises that manifest without this PR. It pins a source list, four header search paths, six defines and two relative package paths that hold only because autolinking uses a symlink. Any of those can break on a React Native bump, silently.

Base is main because a pull request's base must be a branch in the base repository, and this one comes from a fork. The first two commits belong to #4043; this PR's own change is the third — review it alone via 5f6ae3d. The full diff reduces once #4043 lands. Push spm-support to this repository and I will retarget the base for real stacked review.

What is here

spm-example/: a bare React Native 0.87.1 app, no CocoaPods, drawing a Skia canvas, plus the build-test-ios-spm job that installs and builds it.

It sits outside the yarn workspace on purpose: SwiftPM needs React Native 0.87 or newer, apps/example is on 0.83.1, and the two resolutions must not collide. It is therefore not a turbo workspace, so root yarn lint and yarn test do not reach it.

Four deliberate oddities:

  • No lockfile. react and react-native are pinned exactly, so the native build stays deterministic and CI installs with npm install. This keeps a 12,000-line generated file out of review.
  • ios/Podfile is not for CocoaPods. React Native's CLI locates the iOS project by finding a Podfile and taking its directory as sourceDir; with none it returns null, and both react-native spm and the Xcode autolinking phase fail with CLI config did not provide project.ios.sourceDir. userConfig.sourceDir only seeds that search, so config cannot override it. The file installs nothing and calls raise, so a stray pod install fails clearly.
  • CI runs spm update, not spm add --deintegrate. The .xcodeproj is committed already injected, and an injected project resolves to update, which also keeps CocoaPods off the runner.
  • No HERMES_CLI_PATH committed. React Native 0.87.1's injector writes an absolute path to hermesc into the project. The build does not need it, since react-native-xcode.sh resolves hermesc itself, and committing it would put one developer's disk layout in the repository. The README documents the strip.

Test plan

The exact CI sequence, from a clean install:

rm -rf node_modules && npm install     # no lockfile → react-native 0.87.1, react 19.2.3
cd ios && npx react-native spm update  # exit 0, "Self-managed: ReactNativeSkia"
xcodebuild -project SpmExample.xcodeproj -scheme SpmExample \
  -configuration Debug -sdk iphonesimulator \
  -destination 'generic/platform=iOS Simulator' CODE_SIGNING_ALLOWED=NO build
  • Debug: ** BUILD SUCCEEDED **. No CocoaPods invoked, and the Podfile's raise never fires.
  • Release builds, bundles and renders on the simulator. The bundling phase resolves hermesc through the fallback, confirming the omitted setting is unnecessary.
  • Red: with Package.swift absent the setup exits 2 — the failure this harness exists to catch.
  • The tree stays clean after a full run, and no committed file contains an absolute path.

build-test-ios-spm has never run anywhere before, so this PR is its first run.

chrfalch and others added 3 commits September 3, 2026 10:59
React Native 0.87 ships preview SwiftPM support, and CocoaPods trunk goes
read-only in December 2026. A library that ships its own Package.swift is
referenced verbatim by autolinking, so this is additive: SwiftPM ignores the
podspec and CocoaPods ignores Package.swift.

Autolinking exposes the library through a symlink under the app's build
directory and resolves the manifest's relative paths against it, so the two
React Native package paths are fixed for every standard app.

Skia's binaries stay out of the package. The manifest prefers the
react-native-skia-apple-ios copy npm already installs for the CocoaPods build
and falls back to the published Swift package, so a checkout that has run
`yarn install` builds without network access.

Two defines the podspec never needed: CocoaPods forces RCT_NEW_ARCH_ENABLED
and RCT_REMOVE_LEGACY_ARCH project-wide, and the SwiftPM path defines neither,
yet Skia's Apple sources still gate on both.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Covers the React Native 0.87 floor, how autolinking resolves the manifest's
relative paths, the two architecture defines CocoaPods supplies but SwiftPM
does not, where the binaries come from, and the stale Package.resolved pin
that silently keeps the previous binary source when switching between them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A bare React Native 0.87.1 app that consumes @shopify/react-native-skia
through Swift Package Manager, with no CocoaPods, plus the CI job that
builds it. It is the only thing that exercises packages/skia/Package.swift.

Ships no lockfile, so CI installs with `npm install`; react and
react-native are pinned exactly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@chrfalch
chrfalch force-pushed the spm-support-example branch from 5f6ae3d to 5b215e3 Compare September 3, 2026 09:05
@chrfalch
chrfalch marked this pull request as ready for review September 3, 2026 09:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant