feat(iOS): ReactNativeDependenciesHeaders sidecar + pure-RN ReactNativeHeaders, published to Maven#57442
Open
chrfalch wants to merge 5 commits into
Open
Conversation
|
Caution Invalid Base Branch The base branch for this PR is |
73226c2 to
c01f55a
Compare
…idecar The binary ReactNativeDependencies.xcframework is FRAMEWORK-type: it cannot carry a HeadersPath key, so its root Headers/ dir is invisible to SwiftPM binaryTargets (verified empirically 2026-07-04 - xcodebuild rejects -headers without -library, and SwiftPM hard-rejects HeadersPath on framework entries). This adds a headers-only LIBRARY-type sidecar, ReactNativeDependenciesHeaders.xcframework, that SwiftPM auto-serves with zero flags: stub static archives paired with per-slice Headers/ holding the seven third-party namespaces (folly, glog, boost, fmt, double-conversion, fast_float, SocketRocket). - headers-xcframework.js (new): dependency-light shared emitter - composeHeadersOnlyXcframework (the stub-archive recipe factored out of buildReactNativeHeadersXcframework), stubSlicesFromXcframework (slice parity derived from the binary artifact's Info.plist, so the sidecar resolves for every platform the binary does), and buildDepsHeadersXcframework with a set-equality gate that fails closed in both directions (declared-but-missing and undeclared namespaces). - compose-framework.js: the deps compose emits and signs the sidecar right after assembling the root Headers/ (slice-uniform content). - prebuild-ios-dependencies.yml: the sidecar ships INSIDE the deps tarball (self-contained for CocoaPods) and as a standalone tarball; cache key bumped and now also hashes compose-framework.js. - reactNativeDependencies.js: consumers extract the sidecar alongside the binary; pre-sidecar tarballs (pinned RN_DEP_VERSION) warn and continue - CocoaPods is unaffected, SwiftPM recomposes it locally. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every namespace now has exactly ONE physical home: RN namespaces in ReactNativeHeaders, third-party deps namespaces in the ReactNativeDependenciesHeaders sidecar / the ReactNativeDependencies pod. Relocated deps copies are what made the 2026-07-03 SocketRocket regression possible (duplicate @interface + poisoned module graph under use_frameworks when a real pod coexisted with relocated copies) - that bug class is now structurally impossible, and the SocketRocket exclusion list is deleted rather than maintained. - headers-spec.js: R2 rewritten; DEPS_NAMESPACES now includes SocketRocket (= the sidecar contents = the artifact's Headers/ dirs, set-equality enforced); DEPS_NAMESPACES_NOT_RELOCATED deleted. - headers-compose.js: RNH stages RN headers only; ensureHeadersLayout also builds the sidecar from the cache slot's deps headers and returns it, so SwiftPM consumers need no published sidecar. - headers-verify.js: structural gate flipped - deps namespaces must be ABSENT from RNH; compile gates take the deps artifact's Headers on the include path (exactly how consumers resolve them). - CocoaPods: NEW ReactNativeDependenciesUtils.configure_aggregate_xcconfig injects $(PODS_ROOT)/ReactNativeDependencies/Headers into the aggregate and every pod target in prebuilt-deps mode, mirroring the rncore injection. Pods previously resolved folly/glog through the globally-injected React-Core-prebuilt/Headers flatten of RNH; after the flip the deps pod is the single global home, so the mirror injection is what keeps arbitrary pods compiling. Verified: headers gate green (include-health, structural, compile smokes vs the deps include path); rn-tester prebuilt static + dynamic (the regression config), helloworld static, source-core+prebuilt-deps (React compiled from source resolves folly via the deps pod), and a source-mode control with an unchanged dependency graph. BREAKING (prebuilt artifacts only): ReactNativeHeaders.xcframework no longer contains folly/glog/boost/fmt/double-conversion/fast_float; consumers reaching them through React-Core-prebuilt/Headers must use the ReactNativeDependencies pod / ReactNativeDependenciesHeaders sidecar paths instead. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
prebuilt + use_frameworks is the exact configuration of the 2026-07-03
SocketRocket dual-copy regression, and no CI lane covered it: the
test-ios-rntester action hard-coupled use-frameworks:true to building
from source. Add a use-prebuilds input ('auto' keeps the historical
coupling for existing callers) and pass use-prebuilds:true from
test_ios_rntester, so its dynamic-frameworks matrix cells now consume
the prebuilt ReactCore + ReactNativeDependencies artifacts built in the
same workflow run. Source-built dynamic frameworks stay covered by
test_ios_rntester_dynamic_frameworks.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…eaders to Maven
Publish the two headers-only xcframeworks as standalone artifacts on
the react-native-artifacts coordinate so SwiftPM consumers can wire
them as separate binaryTargets (they also keep shipping inside the
ReactCore / ReactNativeDependencies tarballs for CocoaPods):
- external-artifacts/build.gradle.kts: four new PublishArtifacts with
classifiers reactnative-headers-{debug,release} and
reactnative-dependencies-headers-{debug,release}.
- prebuild-ios-core.yml: upload the standalone
ReactNativeHeaders<flavor>.xcframework.tar.gz the compose step
already produces (previously only bundled inside the ReactCore
tarball); include it in the workflow cache.
- build-npm-package action: download ReactNativeHeaders* artifacts
(ReactNativeDependenciesHeaders* already rides the existing
ReactNativeDependencies* pattern).
- verifyArtifactsAreOnMaven.js: HEAD-check every classifier tarball,
not just the POM - a release with a missing classifier artifact now
fails verification instead of passing silently.
Validated locally end-to-end with publishReleasePublicationToMavenLocal:
all 12 files + POM land on com.facebook.react:react-native-artifacts
with the expected classifier names.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The verifier now HEAD-checks the POM plus all eight classifier tarballs instead of GETting only the POM; the mocks/assertions follow, and a new case covers a missing classifier behind an existing POM (the exact gap the classifier checks were added to catch). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
069c350 to
017ca51
Compare
90d8f50 to
0c44552
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Step 2 of the prebuilt-deps roadmap: ship the deps headers as a SwiftPM-ready, self-contained artifact and make every header namespace have exactly one physical home.
New artifact:
ReactNativeDependenciesHeaders.xcframework— the binaryReactNativeDependencies.xcframeworkis framework-type, so its rootHeaders/is invisible to SwiftPM binaryTargets (HeadersPathis rejected on framework entries; verified empirically). The deps prebuild now emits a headers-only library-type sidecar (stub archives + per-sliceHeaders/+HeadersPath— the exactReactNativeHeadersrecipe, factored into a sharedheaders-xcframework.jsemitter) carrying all seven deps namespaces incl. SocketRocket, with slice parity derived from the binary artifact's Info.plist. Ships inside the deps tarball and standalone.ReactNativeHeadersgoes pure-RN — the R2 relocation of deps namespaces (and theDEPS_NAMESPACES_NOT_RELOCATEDSocketRocket exclusion list) is deleted. Relocated copies are what enabled the SocketRocket dual-copy regression (duplicate@interface/ poisoned module graph underuse_frameworks!); that bug class is now structurally impossible. Headers gate flipped: deps namespaces must be absent from RNH; the sidecar emitter enforces set-equality withDEPS_NAMESPACESfail-closed in both directions. On the CocoaPods side, a newReactNativeDependenciesUtils.configure_aggregate_xcconfiginjects the deps pod'sHeaders/globally (aggregate + every pod target), mirroring the rncore injection — this replaces the folly/glog resolution pods previously got via the flattenedReact-Core-prebuilt/Headers.CI: prebuilt + dynamic-frameworks lane — the regression's exact config had no coverage (the
test-ios-rntesteraction hard-coupleduse-frameworks:trueto source builds). Newuse-prebuildsinput;test_ios_rntester's dynamic cells now consume the workflow-built prebuilt artifacts.Maven publishing —
ReactNativeHeadersandReactNativeDependenciesHeaderspublish standalone onreact-native-artifacts(classifiersreactnative-headers-*,reactnative-dependencies-headers-*);verifyArtifactsAreOnMavennow HEAD-checks every classifier tarball instead of only the POM.Stacked on #57440. The SwiftPM preview (#57332) rebases on top and wires the sidecar as its 5th binaryTarget.
Changelog:
[IOS] [CHANGED] - Prebuilt artifacts: ReactNativeHeaders is pure-RN; third-party deps headers ship in the new ReactNativeDependenciesHeaders.xcframework sidecar (and the ReactNativeDependencies pod), published standalone to Maven
Test Plan
scripts/ios-prebuild/__tests__, incl. new sidecar set-equality tests)--max-warnings 0), Prettier, Flow (yarn flow-check): cleanUSE_FRAMEWORKS=dynamic✅ (the regression config — verifiedReact-Core-prebuilt/Headerscontains no deps namespaces and the deps pod serves all seven), helloworld static ✅, source-core + prebuilt-deps ✅ (React compiled from source resolves folly via the deps pod), source-mode control with unchanged dependency graph ✅HeadersPath, 7 namespaces, slice parity with the binarypublishReleasePublicationToMavenLocal: all 12 files + POM land with the expected classifier names🤖 Generated with Claude Code