@ngtools/webpack 14.0.2 → 14.0.5

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": "14.0.2",
3
+ "version": "14.0.5",
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",
@@ -36,6 +36,7 @@ export declare class AngularWebpackPlugin {
36
36
  private get compilerCli();
37
37
  get options(): AngularWebpackPluginOptions;
38
38
  apply(compiler: Compiler): void;
39
+ private setupCompilation;
39
40
  private registerWithCompilation;
40
41
  private markResourceUsed;
41
42
  private rebuildRequiredFiles;
package/src/ivy/plugin.js CHANGED
@@ -97,9 +97,8 @@ class AngularWebpackPlugin {
97
97
  get options() {
98
98
  return this.pluginOptions;
99
99
  }
100
- // eslint-disable-next-line max-lines-per-function
101
100
  apply(compiler) {
102
- const { NormalModuleReplacementPlugin, util } = compiler.webpack;
101
+ const { NormalModuleReplacementPlugin, WebpackError, util } = compiler.webpack;
103
102
  this.webpackCreateHash = util.createHash;
104
103
  // Setup file replacements with webpack
105
104
  for (const [key, value] of Object.entries(this.pluginOptions.fileReplacements)) {
@@ -126,124 +125,132 @@ class AngularWebpackPlugin {
126
125
  });
127
126
  // Load the compiler-cli if not already available
128
127
  compiler.hooks.beforeCompile.tapPromise(PLUGIN_NAME, () => this.initializeCompilerCli());
129
- let ngccProcessor;
130
- let resourceLoader;
131
- let previousUnused;
128
+ const compilationState = { pathsPlugin };
132
129
  compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => {
133
- // Register plugin to ensure deterministic emit order in multi-plugin usage
134
- const emitRegistration = this.registerWithCompilation(compilation);
135
- this.watchMode = compiler.watchMode;
136
- // Initialize webpack cache
137
- if (!this.webpackCache && compilation.options.cache) {
138
- this.webpackCache = compilation.getCache(PLUGIN_NAME);
130
+ try {
131
+ this.setupCompilation(compilation, compilationState);
139
132
  }
140
- // Initialize the resource loader if not already setup
141
- if (!resourceLoader) {
142
- resourceLoader = new resource_loader_1.WebpackResourceLoader(this.watchMode);
133
+ catch (error) {
134
+ compilation.errors.push(new WebpackError(`Failed to initialize Angular compilation - ${error instanceof Error ? error.message : error}`));
143
135
  }
144
- // Initialize and process eager ngcc if not already setup
145
- if (!ngccProcessor) {
146
- const { processor, errors, warnings } = initializeNgccProcessor(compiler, this.pluginOptions.tsconfig, this.compilerNgccModule);
147
- processor.process();
148
- warnings.forEach((warning) => (0, diagnostics_1.addWarning)(compilation, warning));
149
- errors.forEach((error) => (0, diagnostics_1.addError)(compilation, error));
150
- ngccProcessor = processor;
136
+ });
137
+ }
138
+ setupCompilation(compilation, state) {
139
+ const compiler = compilation.compiler;
140
+ // Register plugin to ensure deterministic emit order in multi-plugin usage
141
+ const emitRegistration = this.registerWithCompilation(compilation);
142
+ this.watchMode = compiler.watchMode;
143
+ // Initialize webpack cache
144
+ if (!this.webpackCache && compilation.options.cache) {
145
+ this.webpackCache = compilation.getCache(PLUGIN_NAME);
146
+ }
147
+ // Initialize the resource loader if not already setup
148
+ if (!state.resourceLoader) {
149
+ state.resourceLoader = new resource_loader_1.WebpackResourceLoader(this.watchMode);
150
+ }
151
+ // Initialize and process eager ngcc if not already setup
152
+ if (!state.ngccProcessor) {
153
+ const { processor, errors, warnings } = initializeNgccProcessor(compiler, this.pluginOptions.tsconfig, this.compilerNgccModule);
154
+ processor.process();
155
+ warnings.forEach((warning) => (0, diagnostics_1.addWarning)(compilation, warning));
156
+ errors.forEach((error) => (0, diagnostics_1.addError)(compilation, error));
157
+ state.ngccProcessor = processor;
158
+ }
159
+ // Setup and read TypeScript and Angular compiler configuration
160
+ const { compilerOptions, rootNames, errors } = this.loadConfiguration();
161
+ // Create diagnostics reporter and report configuration file errors
162
+ const diagnosticsReporter = (0, diagnostics_1.createDiagnosticsReporter)(compilation, (diagnostic) => this.compilerCli.formatDiagnostics([diagnostic]));
163
+ diagnosticsReporter(errors);
164
+ // Update TypeScript path mapping plugin with new configuration
165
+ state.pathsPlugin.update(compilerOptions);
166
+ // Create a Webpack-based TypeScript compiler host
167
+ const system = (0, system_1.createWebpackSystem)(
168
+ // Webpack lacks an InputFileSytem type definition with sync functions
169
+ compiler.inputFileSystem, (0, paths_1.normalizePath)(compiler.context));
170
+ const host = ts.createIncrementalCompilerHost(compilerOptions, system);
171
+ // Setup source file caching and reuse cache from previous compilation if present
172
+ let cache = this.sourceFileCache;
173
+ let changedFiles;
174
+ if (cache) {
175
+ changedFiles = new Set();
176
+ for (const changedFile of [...compiler.modifiedFiles, ...compiler.removedFiles]) {
177
+ const normalizedChangedFile = (0, paths_1.normalizePath)(changedFile);
178
+ // Invalidate file dependencies
179
+ this.fileDependencies.delete(normalizedChangedFile);
180
+ // Invalidate existing cache
181
+ cache.invalidate(normalizedChangedFile);
182
+ changedFiles.add(normalizedChangedFile);
151
183
  }
152
- // Setup and read TypeScript and Angular compiler configuration
153
- const { compilerOptions, rootNames, errors } = this.loadConfiguration();
154
- // Create diagnostics reporter and report configuration file errors
155
- const diagnosticsReporter = (0, diagnostics_1.createDiagnosticsReporter)(compilation, (diagnostic) => this.compilerCli.formatDiagnostics([diagnostic]));
156
- diagnosticsReporter(errors);
157
- // Update TypeScript path mapping plugin with new configuration
158
- pathsPlugin.update(compilerOptions);
159
- // Create a Webpack-based TypeScript compiler host
160
- const system = (0, system_1.createWebpackSystem)(
161
- // Webpack lacks an InputFileSytem type definition with sync functions
162
- compiler.inputFileSystem, (0, paths_1.normalizePath)(compiler.context));
163
- const host = ts.createIncrementalCompilerHost(compilerOptions, system);
164
- // Setup source file caching and reuse cache from previous compilation if present
165
- let cache = this.sourceFileCache;
166
- let changedFiles;
167
- if (cache) {
168
- changedFiles = new Set();
169
- for (const changedFile of [...compiler.modifiedFiles, ...compiler.removedFiles]) {
170
- const normalizedChangedFile = (0, paths_1.normalizePath)(changedFile);
171
- // Invalidate file dependencies
172
- this.fileDependencies.delete(normalizedChangedFile);
173
- // Invalidate existing cache
174
- cache.invalidate(normalizedChangedFile);
175
- changedFiles.add(normalizedChangedFile);
176
- }
184
+ }
185
+ else {
186
+ // Initialize a new cache
187
+ cache = new cache_1.SourceFileCache();
188
+ // Only store cache if in watch mode
189
+ if (this.watchMode) {
190
+ this.sourceFileCache = cache;
177
191
  }
178
- else {
179
- // Initialize a new cache
180
- cache = new cache_1.SourceFileCache();
181
- // Only store cache if in watch mode
182
- if (this.watchMode) {
183
- this.sourceFileCache = cache;
192
+ }
193
+ (0, host_1.augmentHostWithCaching)(host, cache);
194
+ const moduleResolutionCache = ts.createModuleResolutionCache(host.getCurrentDirectory(), host.getCanonicalFileName.bind(host), compilerOptions);
195
+ // Setup source file dependency collection
196
+ (0, host_1.augmentHostWithDependencyCollection)(host, this.fileDependencies, moduleResolutionCache);
197
+ // Setup on demand ngcc
198
+ (0, host_1.augmentHostWithNgcc)(host, state.ngccProcessor, moduleResolutionCache);
199
+ // Setup resource loading
200
+ state.resourceLoader.update(compilation, changedFiles);
201
+ (0, host_1.augmentHostWithResources)(host, state.resourceLoader, {
202
+ directTemplateLoading: this.pluginOptions.directTemplateLoading,
203
+ inlineStyleFileExtension: this.pluginOptions.inlineStyleFileExtension,
204
+ });
205
+ // Setup source file adjustment options
206
+ (0, host_1.augmentHostWithReplacements)(host, this.pluginOptions.fileReplacements, moduleResolutionCache);
207
+ (0, host_1.augmentHostWithSubstitutions)(host, this.pluginOptions.substitutions);
208
+ // Create the file emitter used by the webpack loader
209
+ const { fileEmitter, builder, internalFiles } = this.pluginOptions.jitMode
210
+ ? this.updateJitProgram(compilerOptions, rootNames, host, diagnosticsReporter)
211
+ : this.updateAotProgram(compilerOptions, rootNames, host, diagnosticsReporter, state.resourceLoader);
212
+ // Set of files used during the unused TypeScript file analysis
213
+ const currentUnused = new Set();
214
+ for (const sourceFile of builder.getSourceFiles()) {
215
+ if (internalFiles === null || internalFiles === void 0 ? void 0 : internalFiles.has(sourceFile)) {
216
+ continue;
217
+ }
218
+ // Ensure all program files are considered part of the compilation and will be watched.
219
+ // Webpack does not normalize paths. Therefore, we need to normalize the path with FS seperators.
220
+ compilation.fileDependencies.add((0, paths_1.externalizePath)(sourceFile.fileName));
221
+ // Add all non-declaration files to the initial set of unused files. The set will be
222
+ // analyzed and pruned after all Webpack modules are finished building.
223
+ if (!sourceFile.isDeclarationFile) {
224
+ currentUnused.add((0, paths_1.normalizePath)(sourceFile.fileName));
225
+ }
226
+ }
227
+ compilation.hooks.finishModules.tapPromise(PLUGIN_NAME, async (modules) => {
228
+ var _a, _b;
229
+ // Rebuild any remaining AOT required modules
230
+ await this.rebuildRequiredFiles(modules, compilation, fileEmitter);
231
+ // Clear out the Webpack compilation to avoid an extra retaining reference
232
+ (_a = state.resourceLoader) === null || _a === void 0 ? void 0 : _a.clearParentCompilation();
233
+ // Analyze program for unused files
234
+ if (compilation.errors.length > 0) {
235
+ return;
236
+ }
237
+ for (const webpackModule of modules) {
238
+ const resource = webpackModule.resource;
239
+ if (resource) {
240
+ this.markResourceUsed((0, paths_1.normalizePath)(resource), currentUnused);
184
241
  }
185
242
  }
186
- (0, host_1.augmentHostWithCaching)(host, cache);
187
- const moduleResolutionCache = ts.createModuleResolutionCache(host.getCurrentDirectory(), host.getCanonicalFileName.bind(host), compilerOptions);
188
- // Setup source file dependency collection
189
- (0, host_1.augmentHostWithDependencyCollection)(host, this.fileDependencies, moduleResolutionCache);
190
- // Setup on demand ngcc
191
- (0, host_1.augmentHostWithNgcc)(host, ngccProcessor, moduleResolutionCache);
192
- // Setup resource loading
193
- resourceLoader.update(compilation, changedFiles);
194
- (0, host_1.augmentHostWithResources)(host, resourceLoader, {
195
- directTemplateLoading: this.pluginOptions.directTemplateLoading,
196
- inlineStyleFileExtension: this.pluginOptions.inlineStyleFileExtension,
197
- });
198
- // Setup source file adjustment options
199
- (0, host_1.augmentHostWithReplacements)(host, this.pluginOptions.fileReplacements, moduleResolutionCache);
200
- (0, host_1.augmentHostWithSubstitutions)(host, this.pluginOptions.substitutions);
201
- // Create the file emitter used by the webpack loader
202
- const { fileEmitter, builder, internalFiles } = this.pluginOptions.jitMode
203
- ? this.updateJitProgram(compilerOptions, rootNames, host, diagnosticsReporter)
204
- : this.updateAotProgram(compilerOptions, rootNames, host, diagnosticsReporter, resourceLoader);
205
- // Set of files used during the unused TypeScript file analysis
206
- const currentUnused = new Set();
207
- for (const sourceFile of builder.getSourceFiles()) {
208
- if (internalFiles === null || internalFiles === void 0 ? void 0 : internalFiles.has(sourceFile)) {
243
+ for (const unused of currentUnused) {
244
+ if ((_b = state.previousUnused) === null || _b === void 0 ? void 0 : _b.has(unused)) {
209
245
  continue;
210
246
  }
211
- // Ensure all program files are considered part of the compilation and will be watched.
212
- // Webpack does not normalize paths. Therefore, we need to normalize the path with FS seperators.
213
- compilation.fileDependencies.add((0, paths_1.externalizePath)(sourceFile.fileName));
214
- // Add all non-declaration files to the initial set of unused files. The set will be
215
- // analyzed and pruned after all Webpack modules are finished building.
216
- if (!sourceFile.isDeclarationFile) {
217
- currentUnused.add((0, paths_1.normalizePath)(sourceFile.fileName));
218
- }
247
+ (0, diagnostics_1.addWarning)(compilation, `${unused} is part of the TypeScript compilation but it's unused.\n` +
248
+ `Add only entry points to the 'files' or 'include' properties in your tsconfig.`);
219
249
  }
220
- compilation.hooks.finishModules.tapPromise(PLUGIN_NAME, async (modules) => {
221
- // Rebuild any remaining AOT required modules
222
- await this.rebuildRequiredFiles(modules, compilation, fileEmitter);
223
- // Clear out the Webpack compilation to avoid an extra retaining reference
224
- resourceLoader === null || resourceLoader === void 0 ? void 0 : resourceLoader.clearParentCompilation();
225
- // Analyze program for unused files
226
- if (compilation.errors.length > 0) {
227
- return;
228
- }
229
- for (const webpackModule of modules) {
230
- const resource = webpackModule.resource;
231
- if (resource) {
232
- this.markResourceUsed((0, paths_1.normalizePath)(resource), currentUnused);
233
- }
234
- }
235
- for (const unused of currentUnused) {
236
- if (previousUnused && previousUnused.has(unused)) {
237
- continue;
238
- }
239
- (0, diagnostics_1.addWarning)(compilation, `${unused} is part of the TypeScript compilation but it's unused.\n` +
240
- `Add only entry points to the 'files' or 'include' properties in your tsconfig.`);
241
- }
242
- previousUnused = currentUnused;
243
- });
244
- // Store file emitter for loader usage
245
- emitRegistration.update(fileEmitter);
250
+ state.previousUnused = currentUnused;
246
251
  });
252
+ // Store file emitter for loader usage
253
+ emitRegistration.update(fileEmitter);
247
254
  }
248
255
  registerWithCompilation(compilation) {
249
256
  let fileEmitters = compilationFileEmitters.get(compilation);
@@ -24,7 +24,7 @@ export declare class NgccProcessor {
24
24
  constructor(compilerNgcc: typeof import('@angular/compiler-cli/ngcc'), propertiesToConsider: string[], compilationWarnings: (Error | string)[], compilationErrors: (Error | string)[], basePath: string, tsConfigPath: string, inputFileSystem: InputFileSystem, resolver: ResolverWithOptions);
25
25
  /** Process the entire node modules tree. */
26
26
  process(): void;
27
- /** Process a module and it's depedencies. */
27
+ /** Process a module and its dependencies. */
28
28
  processModule(moduleName: string, resolvedModule: ts.ResolvedModule | ts.ResolvedTypeReferenceDirective): void;
29
29
  invalidate(fileName: string): void;
30
30
  /**
@@ -59,8 +59,10 @@ class NgccProcessor {
59
59
  }
60
60
  /** Process the entire node modules tree. */
61
61
  process() {
62
- // Under Bazel when running in sandbox mode parts of the filesystem is read-only.
63
- if (process.env.BAZEL_TARGET) {
62
+ // Under Bazel when running in sandbox mode parts of the filesystem is read-only, or when using
63
+ // Yarn PnP there may not be a node_modules directory. ngcc can't run in those cases, so the
64
+ // processing is skipped.
65
+ if (process.env.BAZEL_TARGET || !this._nodeModulesDirectory) {
64
66
  return;
65
67
  }
66
68
  // Skip if node_modules are read-only
@@ -115,24 +117,30 @@ class NgccProcessor {
115
117
  // that we cannot setup multiple cluster masters with different options.
116
118
  // - We will not be able to have concurrent builds otherwise Ex: App-Shell,
117
119
  // as NGCC will create a lock file for both builds and it will cause builds to fails.
118
- const { status, error } = (0, child_process_1.spawnSync)(process.execPath, [
119
- this.compilerNgcc.ngccMainFilePath,
120
- '--source' /** basePath */,
121
- this._nodeModulesDirectory,
122
- '--properties' /** propertiesToConsider */,
123
- ...this.propertiesToConsider,
124
- '--first-only' /** compileAllFormats */,
125
- '--create-ivy-entry-points' /** createNewEntryPointFormats */,
126
- '--async',
127
- '--tsconfig' /** tsConfigPath */,
128
- this.tsConfigPath,
129
- '--use-program-dependencies',
130
- ], {
131
- stdio: ['inherit', process.stderr, process.stderr],
132
- });
133
- if (status !== 0) {
134
- const errorMessage = (error === null || error === void 0 ? void 0 : error.message) || '';
135
- throw new Error(errorMessage + `NGCC failed${errorMessage ? ', see above' : ''}.`);
120
+ const originalProcessTitle = process.title;
121
+ try {
122
+ const { status, error } = (0, child_process_1.spawnSync)(process.execPath, [
123
+ this.compilerNgcc.ngccMainFilePath,
124
+ '--source' /** basePath */,
125
+ this._nodeModulesDirectory,
126
+ '--properties' /** propertiesToConsider */,
127
+ ...this.propertiesToConsider,
128
+ '--first-only' /** compileAllFormats */,
129
+ '--create-ivy-entry-points' /** createNewEntryPointFormats */,
130
+ '--async',
131
+ '--tsconfig' /** tsConfigPath */,
132
+ this.tsConfigPath,
133
+ '--use-program-dependencies',
134
+ ], {
135
+ stdio: ['inherit', process.stderr, process.stderr],
136
+ });
137
+ if (status !== 0) {
138
+ const errorMessage = (error === null || error === void 0 ? void 0 : error.message) || '';
139
+ throw new Error(errorMessage + `NGCC failed${errorMessage ? ', see above' : ''}.`);
140
+ }
141
+ }
142
+ finally {
143
+ process.title = originalProcessTitle;
136
144
  }
137
145
  (0, benchmark_1.timeEnd)(timeLabel);
138
146
  // ngcc was successful so if a run hash was generated, write it for next time
@@ -148,14 +156,16 @@ class NgccProcessor {
148
156
  }
149
157
  }
150
158
  }
151
- /** Process a module and it's depedencies. */
159
+ /** Process a module and its dependencies. */
152
160
  processModule(moduleName, resolvedModule) {
153
161
  var _a, _b;
154
162
  const resolvedFileName = resolvedModule.resolvedFileName;
155
- if (!resolvedFileName ||
163
+ if (!this._nodeModulesDirectory ||
164
+ !resolvedFileName ||
156
165
  moduleName.startsWith('.') ||
157
166
  this._processedModules.has(resolvedFileName)) {
158
- // Skip when module is unknown, relative or NGCC compiler is not found or already processed.
167
+ // Skip when module_modules directory is not present, module is unknown, relative or the
168
+ // NGCC compiler is not found or already processed.
159
169
  return;
160
170
  }
161
171
  const packageJsonPath = this.tryResolvePackage(moduleName, resolvedFileName);
@@ -210,7 +220,7 @@ class NgccProcessor {
210
220
  }
211
221
  current = path.dirname(current);
212
222
  }
213
- throw new Error(`Cannot locate the 'node_modules' directory.`);
223
+ return null;
214
224
  }
215
225
  findPackageManagerLockFile(projectBasePath) {
216
226
  for (const lockFile of ['yarn.lock', 'pnpm-lock.yaml', 'package-lock.json']) {