From 391d60cc3d0fafed9ab0a0c82a8f5000dde1273b Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Sun, 29 Nov 2020 15:21:37 -0500 Subject: [PATCH] fix(@ngtools/webpack): remove use of Webpack compilation fileTimestamps property The `fileTimestamps` property on the Webpack compilation object no longer exists with Webpack 5. This change uses the Webpack compiler's property of the same name instead. The cache invalidation is also moved to a separate file and now calculates the changed file set as well. This eliminates the second iteration of the file timestamps within the resource loader. --- packages/ngtools/webpack/src/ivy/cache.ts | 30 +++++++++++++++++++ packages/ngtools/webpack/src/ivy/plugin.ts | 17 +++++------ .../ngtools/webpack/src/resource_loader.ts | 19 +++++------- 3 files changed, 44 insertions(+), 22 deletions(-) create mode 100644 packages/ngtools/webpack/src/ivy/cache.ts diff --git a/packages/ngtools/webpack/src/ivy/cache.ts b/packages/ngtools/webpack/src/ivy/cache.ts new file mode 100644 index 000000000000..817d52b496ae --- /dev/null +++ b/packages/ngtools/webpack/src/ivy/cache.ts @@ -0,0 +1,30 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import * as ts from 'typescript'; +import { normalizePath } from './paths'; + +export class SourceFileCache extends Map { + invalidate( + fileTimestamps: Map, + buildTimestamp: number, + ): Set { + const changedFiles = new Set(); + for (const [file, timeOrEntry] of fileTimestamps) { + const time = + timeOrEntry && (typeof timeOrEntry === 'number' ? timeOrEntry : timeOrEntry.timestamp); + if (time === null || buildTimestamp < time) { + // Cache stores paths using the POSIX directory separator + const normalizedFile = normalizePath(file); + this.delete(normalizedFile); + changedFiles.add(normalizedFile); + } + } + + return changedFiles; + } +} diff --git a/packages/ngtools/webpack/src/ivy/plugin.ts b/packages/ngtools/webpack/src/ivy/plugin.ts index c1d784ea0f07..c117edf4271f 100644 --- a/packages/ngtools/webpack/src/ivy/plugin.ts +++ b/packages/ngtools/webpack/src/ivy/plugin.ts @@ -20,6 +20,7 @@ import { TypeScriptPathsPlugin } from '../paths-plugin'; import { WebpackResourceLoader } from '../resource_loader'; import { addError, addWarning } from '../webpack-diagnostics'; import { isWebpackFiveOrHigher, mergeResolverMainFields } from '../webpack-version'; +import { SourceFileCache } from './cache'; import { DiagnosticsReporter, createDiagnosticsReporter } from './diagnostics'; import { augmentHostWithCaching, @@ -81,7 +82,7 @@ export class AngularWebpackPlugin { private watchMode?: boolean; private ngtscNextProgram?: NgtscProgram; private builder?: ts.EmitAndSemanticDiagnosticsBuilderProgram; - private sourceFileCache?: Map; + private sourceFileCache?: SourceFileCache; private buildTimestamp!: number; private readonly lazyRouteMap: Record = {}; private readonly requiredFilesToEmit = new Set(); @@ -186,17 +187,13 @@ export class AngularWebpackPlugin { // Setup source file caching and reuse cache from previous compilation if present let cache = this.sourceFileCache; + let changedFiles; if (cache) { - // Invalidate existing cache based on compilation file timestamps - for (const [file, time] of compilation.fileTimestamps) { - if (this.buildTimestamp < time) { - // Cache stores paths using the POSIX directory separator - cache.delete(normalizePath(file)); - } - } + // Invalidate existing cache based on compiler file timestamps + changedFiles = cache.invalidate(compiler.fileTimestamps, this.buildTimestamp); } else { // Initialize a new cache - cache = new Map(); + cache = new SourceFileCache(); // Only store cache if in watch mode if (this.watchMode) { this.sourceFileCache = cache; @@ -215,7 +212,7 @@ export class AngularWebpackPlugin { augmentHostWithNgcc(host, ngccProcessor, moduleResolutionCache); // Setup resource loading - resourceLoader.update(compilation); + resourceLoader.update(compilation, changedFiles); augmentHostWithResources(host, resourceLoader, { directTemplateLoading: this.pluginOptions.directTemplateLoading, }); diff --git a/packages/ngtools/webpack/src/resource_loader.ts b/packages/ngtools/webpack/src/resource_loader.ts index f3175c4b1dc4..254b5f8e3e0a 100644 --- a/packages/ngtools/webpack/src/resource_loader.ts +++ b/packages/ngtools/webpack/src/resource_loader.ts @@ -32,27 +32,22 @@ export class WebpackResourceLoader { private _cachedSources = new Map(); private _cachedEvaluatedSources = new Map(); - private buildTimestamp?: number; - public changedFiles = new Set(); + public changedFiles?: Iterable; - update(parentCompilation: import('webpack').compilation.Compilation) { + update(parentCompilation: import('webpack').compilation.Compilation, changedFiles?: Iterable) { this._parentCompilation = parentCompilation; this._context = parentCompilation.context; // Update changed file list - if (this.buildTimestamp !== undefined) { - this.changedFiles.clear(); - for (const [file, time] of parentCompilation.fileTimestamps) { - if (this.buildTimestamp < time) { - this.changedFiles.add(normalizePath(file)); - } - } - } - this.buildTimestamp = Date.now(); + this.changedFiles = changedFiles; } getModifiedResourceFiles() { const modifiedResources = new Set(); + if (!this.changedFiles) { + return modifiedResources; + } + for (const changedFile of this.changedFiles) { this.getAffectedResources( changedFile,