@ngtools/webpack 11.2.0-rc.1 → 11.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ngtools/webpack",
3
- "version": "11.2.0-rc.1",
3
+ "version": "11.2.0",
4
4
  "description": "Webpack plugin that AoT compiles your Angular components and modules.",
5
5
  "main": "./src/index.js",
6
6
  "typings": "src/index.d.ts",
@@ -25,7 +25,7 @@
25
25
  },
26
26
  "homepage": "https://github.com/angular/angular-cli",
27
27
  "dependencies": {
28
- "@angular-devkit/core": "11.2.0-rc.1",
28
+ "@angular-devkit/core": "11.2.0",
29
29
  "enhanced-resolve": "5.7.0",
30
30
  "webpack-sources": "2.2.0"
31
31
  },
@@ -27,11 +27,14 @@ export declare class AngularWebpackPlugin {
27
27
  private buildTimestamp;
28
28
  private readonly lazyRouteMap;
29
29
  private readonly requiredFilesToEmit;
30
+ private readonly requiredFilesToEmitCache;
31
+ private readonly fileEmitHistory;
30
32
  constructor(options?: Partial<AngularPluginOptions>);
31
33
  get options(): AngularPluginOptions;
32
34
  apply(compiler: Compiler & {
33
35
  watchMode?: boolean;
34
36
  }): void;
37
+ private rebuildRequiredFiles;
35
38
  private loadConfiguration;
36
39
  private updateAotProgram;
37
40
  private updateJitProgram;
package/src/ivy/plugin.js CHANGED
@@ -10,6 +10,7 @@ exports.AngularWebpackPlugin = void 0;
10
10
  */
11
11
  const compiler_cli_1 = require("@angular/compiler-cli");
12
12
  const program_1 = require("@angular/compiler-cli/src/ngtsc/program");
13
+ const crypto_1 = require("crypto");
13
14
  const path = require("path");
14
15
  const ts = require("typescript");
15
16
  const webpack_1 = require("webpack");
@@ -34,11 +35,16 @@ function initializeNgccProcessor(compiler, tsconfig) {
34
35
  const processor = new ngcc_processor_1.NgccProcessor(mainFields, warnings, errors, compiler.context, tsconfig, inputFileSystem, (_b = webpackOptions.resolve) === null || _b === void 0 ? void 0 : _b.symlinks);
35
36
  return { processor, errors, warnings };
36
37
  }
38
+ function hashContent(content) {
39
+ return crypto_1.createHash('md5').update(content).digest();
40
+ }
37
41
  const PLUGIN_NAME = 'angular-compiler';
38
42
  class AngularWebpackPlugin {
39
43
  constructor(options = {}) {
40
44
  this.lazyRouteMap = {};
41
45
  this.requiredFilesToEmit = new Set();
46
+ this.requiredFilesToEmitCache = new Map();
47
+ this.fileEmitHistory = new Map();
42
48
  this.pluginOptions = {
43
49
  emitClassMetadata: false,
44
50
  emitNgModuleScope: false,
@@ -152,19 +158,7 @@ class AngularWebpackPlugin {
152
158
  }
153
159
  compilation.hooks.finishModules.tapPromise(PLUGIN_NAME, async (modules) => {
154
160
  // Rebuild any remaining AOT required modules
155
- const rebuild = (filename) => new Promise((resolve) => {
156
- const module = modules.find(({ resource }) => resource && paths_1.normalizePath(resource) === filename);
157
- if (!module) {
158
- resolve();
159
- }
160
- else {
161
- compilation.rebuildModule(module, resolve);
162
- }
163
- });
164
- for (const requiredFile of this.requiredFilesToEmit) {
165
- await rebuild(requiredFile);
166
- }
167
- this.requiredFilesToEmit.clear();
161
+ await this.rebuildRequiredFiles(modules, compilation, fileEmitter);
168
162
  // Analyze program for unused files
169
163
  if (compilation.errors.length > 0) {
170
164
  return;
@@ -192,6 +186,41 @@ class AngularWebpackPlugin {
192
186
  compilation[symbol_1.AngularPluginSymbol] = fileEmitter;
193
187
  });
194
188
  }
189
+ async rebuildRequiredFiles(modules, compilation, fileEmitter) {
190
+ if (this.requiredFilesToEmit.size === 0) {
191
+ return;
192
+ }
193
+ const rebuild = (webpackModule) => new Promise((resolve) => compilation.rebuildModule(webpackModule, resolve));
194
+ const filesToRebuild = new Set();
195
+ for (const requiredFile of this.requiredFilesToEmit) {
196
+ const history = this.fileEmitHistory.get(requiredFile);
197
+ if (history) {
198
+ const emitResult = await fileEmitter(requiredFile);
199
+ if ((emitResult === null || emitResult === void 0 ? void 0 : emitResult.content) === undefined ||
200
+ history.length !== emitResult.content.length ||
201
+ emitResult.hash === undefined ||
202
+ Buffer.compare(history.hash, emitResult.hash) !== 0) {
203
+ // New emit result is different so rebuild using new emit result
204
+ this.requiredFilesToEmitCache.set(requiredFile, emitResult);
205
+ filesToRebuild.add(requiredFile);
206
+ }
207
+ }
208
+ else {
209
+ // No emit history so rebuild
210
+ filesToRebuild.add(requiredFile);
211
+ }
212
+ }
213
+ if (filesToRebuild.size > 0) {
214
+ for (const webpackModule of [...modules]) {
215
+ const resource = webpackModule.resource;
216
+ if (resource && filesToRebuild.has(paths_1.normalizePath(resource))) {
217
+ await rebuild(webpackModule);
218
+ }
219
+ }
220
+ }
221
+ this.requiredFilesToEmit.clear();
222
+ this.requiredFilesToEmitCache.clear();
223
+ }
195
224
  loadConfiguration(compilation) {
196
225
  const { options: compilerOptions, rootNames, errors } = compiler_cli_1.readConfiguration(this.pluginOptions.tsconfig, this.pluginOptions.compilerOptions);
197
226
  compilerOptions.enableIvy = true;
@@ -355,12 +384,15 @@ class AngularWebpackPlugin {
355
384
  }
356
385
  createFileEmitter(program, transformers = {}, getExtraDependencies, onAfterEmit) {
357
386
  return async (file) => {
387
+ if (this.requiredFilesToEmitCache.has(file)) {
388
+ return this.requiredFilesToEmitCache.get(file);
389
+ }
358
390
  const sourceFile = program.getSourceFile(file);
359
391
  if (!sourceFile) {
360
392
  return undefined;
361
393
  }
362
- let content = undefined;
363
- let map = undefined;
394
+ let content;
395
+ let map;
364
396
  program.emit(sourceFile, (filename, data) => {
365
397
  if (filename.endsWith('.map')) {
366
398
  map = data;
@@ -370,11 +402,17 @@ class AngularWebpackPlugin {
370
402
  }
371
403
  }, undefined, undefined, transformers);
372
404
  onAfterEmit === null || onAfterEmit === void 0 ? void 0 : onAfterEmit(sourceFile);
405
+ let hash;
406
+ if (content !== undefined && this.watchMode) {
407
+ // Capture emit history info for Angular rebuild analysis
408
+ hash = hashContent(content);
409
+ this.fileEmitHistory.set(file, { length: content.length, hash });
410
+ }
373
411
  const dependencies = [
374
412
  ...program.getAllDependencies(sourceFile),
375
413
  ...getExtraDependencies(sourceFile),
376
414
  ].map(paths_1.externalizePath);
377
- return { content, map, dependencies };
415
+ return { content, map, dependencies, hash };
378
416
  };
379
417
  }
380
418
  }
@@ -10,5 +10,6 @@ export interface EmitFileResult {
10
10
  content?: string;
11
11
  map?: string;
12
12
  dependencies: readonly string[];
13
+ hash?: Uint8Array;
13
14
  }
14
15
  export declare type FileEmitter = (file: string) => Promise<EmitFileResult | undefined>;