From 40d32d6296e4af1e21533f7ed13df10d6cfcb278 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Wed, 21 Jun 2023 14:45:24 -0400 Subject: [PATCH] fix(@angular-devkit/build-angular): watch all bundler provided inputs with esbuild builder When using the esbuild-based browser application builder in watch mode (including `ng serve`), all input files provided by the bundler via the internal metafile information will now be watched and will trigger rebuilds if changed. This allows for files outside of the TypeScript compilation that are also outside of the project source root to be watched. This situation can be encountered in monorepo setups where library code is directly referenced within an application. --- .../src/tools/esbuild/angular/aot-compilation.ts | 5 ++++- .../src/tools/esbuild/bundler-context.ts | 15 ++++++++++++++- .../src/tools/esbuild/bundler-execution-result.ts | 7 ++++++- .../build_angular/src/tools/esbuild/watcher.ts | 4 +++- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/packages/angular_devkit/build_angular/src/tools/esbuild/angular/aot-compilation.ts b/packages/angular_devkit/build_angular/src/tools/esbuild/angular/aot-compilation.ts index 84a59e40a7b9..1b203c18c5e4 100644 --- a/packages/angular_devkit/build_angular/src/tools/esbuild/angular/aot-compilation.ts +++ b/packages/angular_devkit/build_angular/src/tools/esbuild/angular/aot-compilation.ts @@ -103,7 +103,10 @@ export class AotCompilation extends AngularCompilation { const referencedFiles = typeScriptProgram .getSourceFiles() .filter((sourceFile) => !angularCompiler.ignoreForEmit.has(sourceFile)) - .map((sourceFile) => sourceFile.fileName); + .flatMap((sourceFile) => [ + sourceFile.fileName, + ...angularCompiler.getResourceDependencies(sourceFile), + ]); return { affectedFiles, compilerOptions, referencedFiles }; } diff --git a/packages/angular_devkit/build_angular/src/tools/esbuild/bundler-context.ts b/packages/angular_devkit/build_angular/src/tools/esbuild/bundler-context.ts index 50d38243f290..bf06b5c7a5d2 100644 --- a/packages/angular_devkit/build_angular/src/tools/esbuild/bundler-context.ts +++ b/packages/angular_devkit/build_angular/src/tools/esbuild/bundler-context.ts @@ -16,7 +16,7 @@ import { build, context, } from 'esbuild'; -import { basename, extname, relative } from 'node:path'; +import { basename, extname, join, relative } from 'node:path'; export type BundleContextResult = | { errors: Message[]; warnings: Message[] } @@ -48,6 +48,8 @@ export class BundlerContext { #esbuildContext?: BuildContext<{ metafile: true; write: false }>; #esbuildOptions: BuildOptions & { metafile: true; write: false }; + readonly watchFiles = new Set(); + constructor( private workspaceRoot: string, private incremental: boolean, @@ -138,6 +140,17 @@ export class BundlerContext { } } + // Update files that should be watched. + // While this should technically not be linked to incremental mode, incremental is only + // currently enabled with watch mode where watch files are needed. + if (this.incremental) { + this.watchFiles.clear(); + // Add input files except virtual angular files which do not exist on disk + Object.keys(result.metafile.inputs) + .filter((input) => !input.startsWith('angular:')) + .forEach((input) => this.watchFiles.add(join(this.workspaceRoot, input))); + } + // Return if the build encountered any errors if (result.errors.length) { return { diff --git a/packages/angular_devkit/build_angular/src/tools/esbuild/bundler-execution-result.ts b/packages/angular_devkit/build_angular/src/tools/esbuild/bundler-execution-result.ts index d08ba3fd7209..40e879ed2bbe 100644 --- a/packages/angular_devkit/build_angular/src/tools/esbuild/bundler-execution-result.ts +++ b/packages/angular_devkit/build_angular/src/tools/esbuild/bundler-execution-result.ts @@ -49,7 +49,12 @@ export class ExecutionResult { } get watchFiles() { - return this.codeBundleCache?.referencedFiles ?? []; + const files = this.rebuildContexts.flatMap((context) => [...context.watchFiles]); + if (this.codeBundleCache?.referencedFiles) { + files.push(...this.codeBundleCache.referencedFiles); + } + + return files; } createRebuildState(fileChanges: ChangedFiles): RebuildState { diff --git a/packages/angular_devkit/build_angular/src/tools/esbuild/watcher.ts b/packages/angular_devkit/build_angular/src/tools/esbuild/watcher.ts index 053f585b48f7..944430aac95a 100644 --- a/packages/angular_devkit/build_angular/src/tools/esbuild/watcher.ts +++ b/packages/angular_devkit/build_angular/src/tools/esbuild/watcher.ts @@ -36,7 +36,9 @@ export function createWatcher(options?: { ignored?: string[]; }): BuildWatcher { const watcher = new FSWatcher({ - ...options, + usePolling: options?.polling, + interval: options?.interval, + ignored: options?.ignored, disableGlobbing: true, ignoreInitial: true, });