Skip to content

Commit 7e7d721

Browse files
committed
feat(spm): auto-sync detects added/removed native source files
The Xcode auto-sync build phase previously only watched package.json, react-native.config.js, lockfiles, and node_modules mtimes. Adding or removing a source file inside an spm.modules entry or an autolinked dep was invisible — adds were silently skipped (missing from the sources: allowlist) and removes broke the build (allowlist pointed at a vanished file). The autolinker now emits build/generated/autolinking/.spm-sync-watch-paths, a deduped list of every module's source dir it consumed. The build-phase shell extends its staleness checks with `find -newer "$STAMP"` against each watched dir. POSIX directory mtimes update on both add and remove, so a single check covers both cases. Sub-millisecond per dir; the fast path is unchanged when nothing has changed. When triggered, the existing sync runs the autolinker, which regenerates the wrapper Package.swift files and their sources: allowlists.
1 parent 3e6384e commit 7e7d721

2 files changed

Lines changed: 28 additions & 0 deletions

File tree

packages/react-native/scripts/spm/generate-spm-autolinking.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,6 +1296,20 @@ function main(argv /*:: ?: Array<string> */) /*: void */ {
12961296
fs.writeFileSync(outputPath, aggregatorContent, 'utf8');
12971297
log(`Generated: ${path.relative(appRoot, outputPath)}`);
12981298

1299+
// .spm-sync-watch-paths: absolute paths the Xcode auto-sync build phase
1300+
// should watch for add/remove of native source files. Updating the dir
1301+
// mtime via touch/rm of a child file is enough to invalidate the stamp,
1302+
// so the sync re-runs and the `sources:` allowlist is regenerated.
1303+
// Each module's source dir is already known via entryAbsDirs.
1304+
const watchPaths = Array.from(new Set(entryAbsDirs.values()))
1305+
.filter(p => p.length > 0 && fs.existsSync(p))
1306+
.sort();
1307+
fs.writeFileSync(
1308+
path.join(outputDir, '.spm-sync-watch-paths'),
1309+
watchPaths.join('\n') + (watchPaths.length > 0 ? '\n' : ''),
1310+
'utf8',
1311+
);
1312+
12991313
// AutolinkedAggregate is glue; needs at least one source file (Swift, so we
13001314
// sidestep the Obj-C public-headers-dir requirement).
13011315
const aggregateDir = path.join(outputDir, 'AutolinkedAggregate');

packages/react-native/scripts/spm/generate-spm-xcodeproj.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,20 @@ if [ "$STALE" -eq 0 ] && [ "$SRCROOT" != "$PROJECT_ROOT" ]; then
632632
fi
633633
fi
634634
635+
# Check 1.5: watched module source dirs (catches add/remove of source files
636+
# in spm.modules and autolinked deps). Directory mtime updates on both add
637+
# and remove of children, so a single -newer check covers both cases.
638+
WATCH_FILE="$SRCROOT/build/generated/autolinking/.spm-sync-watch-paths"
639+
if [ "$STALE" -eq 0 ] && [ -f "$WATCH_FILE" ]; then
640+
while IFS= read -r DIR; do
641+
[ -z "$DIR" ] && continue
642+
if [ -d "$DIR" ] && [ -n "$(find "$DIR" -newer "$STAMP" -print -quit 2>/dev/null)" ]; then
643+
STALE=1
644+
break
645+
fi
646+
done < "$WATCH_FILE"
647+
fi
648+
635649
# Check 2: codegen spec files changed via git (covers monorepo after git pull)
636650
if [ "$STALE" -eq 0 ] && [ -f "$STAMP" ]; then
637651
STAMP_TIME=$(stat -f %m "$STAMP" 2>/dev/null || stat -c %Y "$STAMP" 2>/dev/null || echo 0)

0 commit comments

Comments
 (0)