Skip to content

Commit e433d7f

Browse files
committed
refactor(@angular-devkit/build-angular): only use rename and change raw events
This commit updates the file watcher to only use rename and change events from raw events and will otherwise rely on all events to capture other file changes. The rename and change events are watch are triggered when using IDEs that use atomic writes. This should improve cross-platform and cross IDE compatibility. (cherry picked from commit 03985a4)
1 parent 46d88a0 commit e433d7f

File tree

1 file changed

+64
-48
lines changed
  • packages/angular_devkit/build_angular/src/tools/esbuild

1 file changed

+64
-48
lines changed

packages/angular_devkit/build_angular/src/tools/esbuild/watcher.ts

+64-48
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88

99
import { FSWatcher } from 'chokidar';
10-
import { normalize } from 'node:path';
10+
import { extname, normalize } from 'node:path';
1111

1212
export class ChangedFiles {
1313
readonly added = new Set<string>();
@@ -98,55 +98,24 @@ export function createWatcher(options?: {
9898
* ... (Nothing)
9999
* ```
100100
*/
101-
watcher.on(watcher.options.useFsEvents ? 'all' : 'raw', (event, path, metadata) => {
102-
switch (event) {
103-
case 'add':
104-
case 'change':
105-
// When using Visual Studio the rename event is fired before a change event when the contents of the file changed
106-
// or instead of `unlink` when the file has been renamed.
107-
case 'unlink':
108-
case 'rename':
109-
// When polling is enabled `watchedPath` can be undefined.
110-
// `path` is always normalized unlike `watchedPath`.
111-
const changedPath = metadata?.watchedPath ? normalize(metadata.watchedPath) : path;
112-
currentEvents ??= new Map();
113-
currentEvents.set(changedPath, event);
114-
break;
115-
default:
101+
watcher
102+
.on('raw', (event, path, { watchedPath }) => {
103+
if (watchedPath && !extname(watchedPath)) {
104+
// Ignore directories, file changes in directories will be fired seperatly.
116105
return;
117-
}
118-
119-
// Wait 250ms from next change to better capture groups of file save operations.
120-
if (!nextWaitTimeout) {
121-
nextWaitTimeout = setTimeout(() => {
122-
nextWaitTimeout = undefined;
123-
const next = nextQueue.shift();
124-
if (next && currentEvents) {
125-
const events = currentEvents;
126-
currentEvents = undefined;
127-
128-
const currentChanges = new ChangedFiles();
129-
for (const [path, event] of events) {
130-
switch (event) {
131-
case 'add':
132-
currentChanges.added.add(path);
133-
break;
134-
case 'change':
135-
currentChanges.modified.add(path);
136-
break;
137-
case 'unlink':
138-
case 'rename':
139-
currentChanges.removed.add(path);
140-
break;
141-
}
142-
}
106+
}
143107

144-
next(currentChanges);
145-
}
146-
}, 250);
147-
nextWaitTimeout?.unref();
148-
}
149-
});
108+
switch (event) {
109+
case 'rename':
110+
case 'change':
111+
// When polling is enabled `watchedPath` can be undefined.
112+
// `path` is always normalized unlike `watchedPath`.
113+
const changedPath = watchedPath ? normalize(watchedPath) : path;
114+
handleFileChange(event, changedPath);
115+
break;
116+
}
117+
})
118+
.on('all', handleFileChange);
150119

151120
return {
152121
[Symbol.asyncIterator]() {
@@ -188,4 +157,51 @@ export function createWatcher(options?: {
188157
}
189158
},
190159
};
160+
161+
function handleFileChange(event: string, path: string): void {
162+
switch (event) {
163+
case 'add':
164+
case 'change':
165+
// When using Visual Studio the rename event is fired before a change event when the contents of the file changed
166+
// or instead of `unlink` when the file has been renamed.
167+
case 'unlink':
168+
case 'rename':
169+
currentEvents ??= new Map();
170+
currentEvents.set(path, event);
171+
break;
172+
default:
173+
return;
174+
}
175+
176+
// Wait 250ms from next change to better capture groups of file save operations.
177+
if (!nextWaitTimeout) {
178+
nextWaitTimeout = setTimeout(() => {
179+
nextWaitTimeout = undefined;
180+
const next = nextQueue.shift();
181+
if (next && currentEvents) {
182+
const events = currentEvents;
183+
currentEvents = undefined;
184+
185+
const currentChanges = new ChangedFiles();
186+
for (const [path, event] of events) {
187+
switch (event) {
188+
case 'add':
189+
currentChanges.added.add(path);
190+
break;
191+
case 'change':
192+
currentChanges.modified.add(path);
193+
break;
194+
case 'unlink':
195+
case 'rename':
196+
currentChanges.removed.add(path);
197+
break;
198+
}
199+
}
200+
201+
next(currentChanges);
202+
}
203+
}, 250);
204+
nextWaitTimeout?.unref();
205+
}
206+
}
191207
}

0 commit comments

Comments
 (0)