Skip to content

Commit cba66a8

Browse files
committed
fix(@angular/build): avoid attempting to watch bundler internal files
The internal bundler (`esbuild`) may use virtual files to represent added content to the output files. This includes names such as `<define:???>` and `<runtime>` to reference object define values and runtime code, respectively. It may also use paths that end with `(disabled):<node_builtin_name>` where `<node_builtin_name>` is one of Node.js' builtin modules. All these cases are now handled by the file watching system and will not be attempted to be watched. Previously these virtual files would be considered removed by the file watching system as they do not actually exist on the file system. (cherry picked from commit 27f7007)
1 parent 009fc37 commit cba66a8

File tree

1 file changed

+28
-8
lines changed

1 file changed

+28
-8
lines changed

packages/angular/build/src/tools/esbuild/bundler-context.ts

+28-8
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
context,
1919
} from 'esbuild';
2020
import assert from 'node:assert';
21+
import { builtinModules } from 'node:module';
2122
import { basename, extname, join, relative } from 'node:path';
2223
import { LoadResultCache, MemoryLoadResultCache } from './load-result-cache';
2324
import { SERVER_GENERATED_EXTERNALS, convertOutputFile } from './utils';
@@ -245,7 +246,7 @@ export class BundlerContext {
245246
// When incremental always add any files from the load result cache
246247
if (this.#loadCache) {
247248
for (const file of this.#loadCache.watchFiles) {
248-
if (!isInternalAngularFileOrEsBuildDefine(file)) {
249+
if (!isInternalAngularFile(file)) {
249250
// watch files are fully resolved paths
250251
this.watchFiles.add(file);
251252
}
@@ -260,10 +261,12 @@ export class BundlerContext {
260261
if (this.incremental) {
261262
// Add input files except virtual angular files which do not exist on disk
262263
for (const input of Object.keys(result.metafile.inputs)) {
263-
if (!isInternalAngularFileOrEsBuildDefine(input)) {
264-
// input file paths are always relative to the workspace root
265-
this.watchFiles.add(join(this.workspaceRoot, input));
264+
if (isInternalAngularFile(input) || isInternalBundlerFile(input)) {
265+
continue;
266266
}
267+
268+
// Input file paths are always relative to the workspace root
269+
this.watchFiles.add(join(this.workspaceRoot, input));
267270
}
268271
}
269272

@@ -417,12 +420,12 @@ export class BundlerContext {
417420
#addErrorsToWatch(result: BuildFailure | BuildResult): void {
418421
for (const error of result.errors) {
419422
let file = error.location?.file;
420-
if (file && !isInternalAngularFileOrEsBuildDefine(file)) {
423+
if (file && !isInternalAngularFile(file)) {
421424
this.watchFiles.add(join(this.workspaceRoot, file));
422425
}
423426
for (const note of error.notes) {
424427
file = note.location?.file;
425-
if (file && !isInternalAngularFileOrEsBuildDefine(file)) {
428+
if (file && !isInternalAngularFile(file)) {
426429
this.watchFiles.add(join(this.workspaceRoot, file));
427430
}
428431
}
@@ -475,6 +478,23 @@ export class BundlerContext {
475478
}
476479
}
477480

478-
function isInternalAngularFileOrEsBuildDefine(file: string) {
479-
return file.startsWith('angular:') || file.startsWith('<define:');
481+
function isInternalAngularFile(file: string) {
482+
return file.startsWith('angular:');
483+
}
484+
485+
function isInternalBundlerFile(file: string) {
486+
// Bundler virtual files such as "<define:???>" or "<runtime>"
487+
if (file[0] === '<' && file.at(-1) === '>') {
488+
return true;
489+
}
490+
491+
const DISABLED_BUILTIN = '(disabled):';
492+
493+
// Disabled node builtins such as "/some/path/(disabled):fs"
494+
const disabledIndex = file.indexOf(DISABLED_BUILTIN);
495+
if (disabledIndex >= 0) {
496+
return builtinModules.includes(file.slice(disabledIndex + DISABLED_BUILTIN.length));
497+
}
498+
499+
return false;
480500
}

0 commit comments

Comments
 (0)