Skip to content

Commit 8b9933b

Browse files
committed
refactor(project): Await file-watcher readiness in BuildServer
The BuildServer constructor used to fire `watchHandler.watch(...)` without awaiting it, so `graph.serve()` could return before chokidar had fully initialised. Source-file changes made immediately afterwards were silently dropped, which surfaced as flaky cache-mode integration tests on Windows where chokidar's ReadDirectoryChangesW backend has noticeably higher startup latency than inotify/FSEvents. Move watcher setup into a `BuildServer.create()` static factory that awaits readiness, and update `ProjectGraph.serve()` to use it.
1 parent c4d0d5c commit 8b9933b

2 files changed

Lines changed: 36 additions & 9 deletions

File tree

packages/project/lib/build/BuildServer.js

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,11 @@ class BuildServer extends EventEmitter {
5252
/**
5353
* Creates a new BuildServer instance
5454
*
55-
* Initializes readers for different project combinations, sets up file watching,
56-
* and optionally performs an initial build of specified dependencies.
55+
* Initializes readers for different project combinations and optionally enqueues an
56+
* initial build of specified dependencies. File watching is set up separately via
57+
* {@link BuildServer.create}, which awaits watcher readiness before returning.
5758
*
58-
* @public
59+
* @private
5960
* @param {@ui5/project/graph/ProjectGraph} graph Project graph containing all projects
6061
* @param {@ui5/project/build/ProjectBuilder} projectBuilder Builder instance for executing builds
6162
* @param {boolean} initialBuildRootProject Whether to build the root project in the initial build
@@ -107,21 +108,47 @@ class BuildServer extends EventEmitter {
107108
}
108109
}
109110
}
111+
}
110112

113+
/**
114+
* Creates a BuildServer and waits for its file watcher to be ready before resolving.
115+
*
116+
* Awaiting watcher readiness avoids a race where source changes made immediately after
117+
* <code>graph.serve()</code> resolves would be missed. The race is most pronounced on
118+
* Windows, where chokidar's <code>ReadDirectoryChangesW</code> backend has noticeably
119+
* higher startup latency than inotify/FSEvents.
120+
*
121+
* @public
122+
* @param {@ui5/project/graph/ProjectGraph} graph Project graph containing all projects
123+
* @param {@ui5/project/build/ProjectBuilder} projectBuilder Builder instance for executing builds
124+
* @param {boolean} initialBuildRootProject Whether to build the root project in the initial build
125+
* @param {string[]} initialBuildIncludedDependencies Project names to include in initial build
126+
* @param {string[]} initialBuildExcludedDependencies Project names to exclude from initial build
127+
* @returns {Promise<BuildServer>} Resolves once the watcher is ready
128+
*/
129+
static async create(
130+
graph, projectBuilder,
131+
initialBuildRootProject, initialBuildIncludedDependencies, initialBuildExcludedDependencies
132+
) {
133+
const buildServer = new BuildServer(
134+
graph, projectBuilder,
135+
initialBuildRootProject, initialBuildIncludedDependencies, initialBuildExcludedDependencies
136+
);
137+
await buildServer.#initWatcher();
138+
return buildServer;
139+
}
140+
141+
async #initWatcher() {
111142
const watchHandler = new WatchHandler();
112143
this.#watchHandler = watchHandler;
113-
const allProjects = graph.getProjects();
114-
watchHandler.watch(allProjects).catch((err) => {
115-
// Error during watch setup
116-
this.emit("error", err);
117-
});
118144
watchHandler.on("error", (err) => {
119145
this.emit("error", err);
120146
});
121147
watchHandler.on("change", (eventType, resourcePath, project) => {
122148
log.verbose(`Source change detected: ${eventType} ${resourcePath} in project '${project.getName()}'`);
123149
this._projectResourceChanged(project, resourcePath, ["add", "unlink", "unlinkDir"].includes(eventType));
124150
});
151+
await watchHandler.watch(this.#graph.getProjects());
125152
}
126153

127154
async destroy() {

packages/project/lib/graph/ProjectGraph.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -791,7 +791,7 @@ class ProjectGraph {
791791
const {
792792
default: BuildServer
793793
} = await import("../build/BuildServer.js");
794-
return new BuildServer(this, builder,
794+
return BuildServer.create(this, builder,
795795
initialBuildRootProject, initialBuildIncludedDependencies, initialBuildExcludedDependencies);
796796
}
797797

0 commit comments

Comments
 (0)