Repository navigation
Conversation
The build-time SwiftPM sync check only watched paths that existed at the last sync. A watched path created later, such as a plugin's precompiled output folder on a fresh clone, never triggered a re-sync. The sync now lists those absent paths in .spm-sync-watch-absent, and the build phase re-syncs when one appears. Existing projects get the new check after running `npx react-native spm update` once.
| const watchPaths = Array.from(new Set(watchCandidates)) | ||
| .filter(p => p.length > 0 && fs.existsSync(p)) | ||
| .sort(); | ||
| for (const name of fs.readdirSync(appRoot)) { |
There was a problem hiding this comment.
What happens to iteration speed in Xcode? Xcode rewrites project.pbxproj whenever a file is added or a setting changes in the IDE, so each of those edits would now trigger a full sync (codegen + autolinking) on the next build. Have we considered watching something narrower, like a hash of only the sections spm owns (e.g. the embed phase), so unrelated project edits don't re-sync?
There was a problem hiding this comment.
You're right. Xcode rewrites project.pbxproj on many IDE edits. I removed the project-file watch from this PR in abf4196. #58827 now records the linked frameworks in .spm-injected.json and makes that file a sync input instead. The marker is committed next to the project, and only spm add and spm update change it. So a teammate's pull of spm changes still starts a sync, and IDE edits do not. I updated the title and description.
| .filter(p => p.length > 0 && fs.existsSync(p)) | ||
| .sort(); | ||
| for (const name of fs.readdirSync(appRoot)) { | ||
| if (name.endsWith('.xcodeproj')) { |
There was a problem hiding this comment.
Nit: should we also check that the entry is a directory, and limit this to the injected project (e.g. via findInjectedXcodeproj)? Right now any top-level *.xcodeproj gets watched, including projects spm doesn't manage.
There was a problem hiding this comment.
This code is gone in abf4196, together with the project-file watch, so no top-level *.xcodeproj is watched now.
| const absentWatchPaths /*: Array<string> */ = []; | ||
| for (const p of Array.from(new Set(watchCandidates)).sort()) { | ||
| if (p.length > 0) { | ||
| (fs.existsSync(p) ? watchPaths : absentWatchPaths).push(p); |
There was a problem hiding this comment.
Is it intended that every dependency's missing root Package.swift and .react-native/ ends up in .spm-sync-watch-absent, not just plugin paths? The check is cheap, but it means a dependency gaining either one now triggers a re-sync. That might be desirable (e.g. after spm scaffold), but it might be worth calling out in the summary or the comment above.
There was a problem hiding this comment.
Yes, this is intended. A root Package.swift or .react-native/ that appears later, for example after spm scaffold, changes how the dependency is detected, so it needs a re-sync. I added a why-comment, a test, and a line in spm-scripts.md in abf4196, and the PR description now mentions it.
Summary:
The SwiftPM build-time sync runs only when its stamp is older than one of the files it watches. A watched path that did not exist at the last sync was dropped from the watch list. So when that path appeared later, the sync did not run.
Examples:
Package.swiftor.react-native/folder. When one appears later, for example afternpx react-native spm scaffold, the dependency is detected differently, but the sync does not run.This PR writes missing watch paths to a new file,
.spm-sync-watch-absent. The stamp is stale when one of those paths now exists. The missing paths do not go to.spm-sync-watch-paths, because projects from older versions treat a missing path in that file as stale and would sync on every build. Those projects get this fix after runningnpx react-native spm updateonce.The paths that can go to
.spm-sync-watch-absent:watchPathsentry that does not exist yetPackage.swiftand.react-native/of each dependency, when they do not existThe docs now tell plugins to list their precompiled-module folder in
watchPaths, but only a folder that the Xcode build does not write to.This PR does not watch
project.pbxproj. Xcode rewrites that file on many edits in the IDE, so watching it would run a full sync after each edit. #58827 makes.spm-injected.jsona watched file instead. Onlyspm addandspm updatechange that file.This PR is independent of #58827. They can land in either order. Both change the generated sync check, so the second one to land needs a rebase.
Changelog:
[IOS] [FIXED] - SwiftPM: the build-time sync now runs again when a watched path that did not exist at the last sync appears.
Test Plan:
Result: 21 suites and 1010 tests pass.
generate-spm-autolinking-test.js:.spm-sync-watch-absentonly. This test failed before the change.Package.swiftor.react-native/lists both paths as absent. The first version of this PR already did this, so the test passed at once. Removing the two paths from the code makes it fail.project.pbxprojis not watched. This test failed before the change.generate-spm-xcodeproj-test.js: runs the shipped bash check under/bin/bash. The stamp is stale only when a path listed as absent now exists.