@ngtools/webpack 13.1.0-next.1 → 13.1.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": "13.1.0-next.1",
3
+ "version": "13.1.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",
@@ -27,7 +27,7 @@
27
27
  "dependencies": {},
28
28
  "peerDependencies": {
29
29
  "@angular/compiler-cli": "^13.0.0 || ^13.1.0-next",
30
- "typescript": "~4.4.3",
30
+ "typescript": ">=4.4.3 <4.6",
31
31
  "webpack": "^5.30.0"
32
32
  },
33
33
  "engines": {
package/src/ivy/loader.js CHANGED
@@ -72,7 +72,9 @@ function angularWebpackLoader(content, map) {
72
72
  callback(undefined, resultContent, resultMap);
73
73
  })
74
74
  .catch((err) => {
75
- callback(err);
75
+ // The below is needed to hide stacktraces from users.
76
+ const message = err instanceof Error ? err.message : err;
77
+ callback(new Error(message));
76
78
  });
77
79
  }
78
80
  exports.angularWebpackLoader = angularWebpackLoader;
package/src/ivy/plugin.js CHANGED
@@ -398,8 +398,10 @@ class AngularWebpackPlugin {
398
398
  };
399
399
  // Required to support asynchronous resource loading
400
400
  // Must be done before creating transformers or getting template diagnostics
401
- const pendingAnalysis = angularCompiler.analyzeAsync().then(() => {
402
- var _a, _b;
401
+ const pendingAnalysis = angularCompiler
402
+ .analyzeAsync()
403
+ .then(() => {
404
+ var _a;
403
405
  this.requiredFilesToEmit.clear();
404
406
  for (const sourceFile of builder.getSourceFiles()) {
405
407
  if (sourceFile.isDeclarationFile) {
@@ -424,29 +426,30 @@ class AngularWebpackPlugin {
424
426
  }
425
427
  }
426
428
  }
427
- // Temporary workaround during transition to ESM-only @angular/compiler-cli
428
- // TODO_ESM: This workaround should be removed prior to the final release of v13
429
- // and replaced with only `this.compilerCli.OptimizeFor`.
430
- const OptimizeFor =
431
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
432
- (_a = this.compilerCli.OptimizeFor) !== null && _a !== void 0 ? _a : require('@angular/compiler-cli/src/ngtsc/typecheck/api').OptimizeFor;
433
429
  // Collect new Angular diagnostics for files affected by changes
430
+ const OptimizeFor = this.compilerCli.OptimizeFor;
434
431
  const optimizeDiagnosticsFor = affectedFiles.size <= DIAGNOSTICS_AFFECTED_THRESHOLD
435
432
  ? OptimizeFor.SingleFile
436
433
  : OptimizeFor.WholeProgram;
437
434
  for (const affectedFile of affectedFiles) {
438
435
  const angularDiagnostics = angularCompiler.getDiagnosticsForFile(affectedFile, optimizeDiagnosticsFor);
439
436
  diagnosticsReporter(angularDiagnostics);
440
- (_b = this.sourceFileCache) === null || _b === void 0 ? void 0 : _b.updateAngularDiagnostics(affectedFile, angularDiagnostics);
437
+ (_a = this.sourceFileCache) === null || _a === void 0 ? void 0 : _a.updateAngularDiagnostics(affectedFile, angularDiagnostics);
441
438
  }
442
- return this.createFileEmitter(builder, (0, transformation_1.mergeTransformers)(angularCompiler.prepareEmit().transformers, transformers), getDependencies, (sourceFile) => {
443
- this.requiredFilesToEmit.delete((0, paths_1.normalizePath)(sourceFile.fileName));
444
- angularCompiler.incrementalDriver.recordSuccessfulEmit(sourceFile);
445
- });
446
- });
439
+ return {
440
+ emitter: this.createFileEmitter(builder, (0, transformation_1.mergeTransformers)(angularCompiler.prepareEmit().transformers, transformers), getDependencies, (sourceFile) => {
441
+ this.requiredFilesToEmit.delete((0, paths_1.normalizePath)(sourceFile.fileName));
442
+ angularCompiler.incrementalDriver.recordSuccessfulEmit(sourceFile);
443
+ }),
444
+ };
445
+ })
446
+ .catch((err) => ({ errorMessage: err instanceof Error ? err.message : `${err}` }));
447
447
  const analyzingFileEmitter = async (file) => {
448
- const innerFileEmitter = await pendingAnalysis;
449
- return innerFileEmitter(file);
448
+ const analysis = await pendingAnalysis;
449
+ if ('errorMessage' in analysis) {
450
+ throw new Error(analysis.errorMessage);
451
+ }
452
+ return analysis.emitter(file);
450
453
  };
451
454
  return {
452
455
  fileEmitter: analyzingFileEmitter,
@@ -524,24 +527,8 @@ class AngularWebpackPlugin {
524
527
  // this, a Function constructor is used to prevent TypeScript from changing the dynamic import.
525
528
  // Once TypeScript provides support for keeping the dynamic import this workaround can
526
529
  // be dropped.
527
- const compilerCliModule = await new Function(`return import('@angular/compiler-cli');`)();
528
- let compilerNgccModule;
529
- try {
530
- compilerNgccModule = await new Function(`return import('@angular/compiler-cli/ngcc');`)();
531
- }
532
- catch {
533
- // If the `exports` field entry is not present then try the file directly.
534
- // TODO_ESM: This try/catch can be removed once the `exports` field is present in `@angular/compiler-cli`
535
- compilerNgccModule = await new Function(`return import('@angular/compiler-cli/ngcc/index.js');`)();
536
- }
537
- // If it is not ESM then the functions needed will be stored in the `default` property.
538
- // TODO_ESM: This conditional can be removed when `@angular/compiler-cli` is ESM only.
539
- this.compilerCliModule = compilerCliModule.readConfiguration
540
- ? compilerCliModule
541
- : compilerCliModule.default;
542
- this.compilerNgccModule = compilerNgccModule.process
543
- ? compilerNgccModule
544
- : compilerNgccModule.default;
530
+ this.compilerCliModule = await new Function(`return import('@angular/compiler-cli');`)();
531
+ this.compilerNgccModule = await new Function(`return import('@angular/compiler-cli/ngcc');`)();
545
532
  }
546
533
  }
547
534
  exports.AngularWebpackPlugin = AngularWebpackPlugin;
@@ -11,7 +11,6 @@ export declare function createAotTransformers(builder: ts.BuilderProgram, option
11
11
  emitNgModuleScope?: boolean;
12
12
  }): ts.CustomTransformers;
13
13
  export declare function createJitTransformers(builder: ts.BuilderProgram, compilerCli: typeof import('@angular/compiler-cli'), options: {
14
- directTemplateLoading?: boolean;
15
14
  inlineStyleFileExtension?: string;
16
15
  }): ts.CustomTransformers;
17
16
  export declare function mergeTransformers(first: ts.CustomTransformers, second: ts.CustomTransformers): ts.CustomTransformers;
@@ -50,7 +50,7 @@ function createJitTransformers(builder, compilerCli, options) {
50
50
  const getTypeChecker = () => builder.getProgram().getTypeChecker();
51
51
  return {
52
52
  before: [
53
- (0, replace_resources_1.replaceResources)(() => true, getTypeChecker, options.directTemplateLoading, options.inlineStyleFileExtension),
53
+ (0, replace_resources_1.replaceResources)(() => true, getTypeChecker, options.inlineStyleFileExtension),
54
54
  compilerCli.constructorParametersDownlevelTransform(builder.getProgram()),
55
55
  ],
56
56
  };
@@ -55,7 +55,6 @@ class NgccProcessor {
55
55
  }
56
56
  /** Process the entire node modules tree. */
57
57
  process() {
58
- var _a;
59
58
  // Under Bazel when running in sandbox mode parts of the filesystem is read-only.
60
59
  if (process.env.BAZEL_TARGET) {
61
60
  return;
@@ -115,19 +114,13 @@ class NgccProcessor {
115
114
  }
116
115
  const timeLabel = 'NgccProcessor.process';
117
116
  (0, benchmark_1.time)(timeLabel);
118
- // Temporary workaround during transition to ESM-only @angular/compiler-cli
119
- // TODO_ESM: This workaround should be removed prior to the final release of v13
120
- // and replaced with only `this.compilerNgcc.ngccMainFilePath`.
121
- const ngccExecutablePath =
122
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
123
- (_a = this.compilerNgcc.ngccMainFilePath) !== null && _a !== void 0 ? _a : require.resolve('@angular/compiler-cli/ngcc/main-ngcc.js');
124
117
  // We spawn instead of using the API because:
125
118
  // - NGCC Async uses clustering which is problematic when used via the API which means
126
119
  // that we cannot setup multiple cluster masters with different options.
127
120
  // - We will not be able to have concurrent builds otherwise Ex: App-Shell,
128
121
  // as NGCC will create a lock file for both builds and it will cause builds to fails.
129
122
  const { status, error } = (0, child_process_1.spawnSync)(process.execPath, [
130
- ngccExecutablePath,
123
+ this.compilerNgcc.ngccMainFilePath,
131
124
  '--source' /** basePath */,
132
125
  this._nodeModulesDirectory,
133
126
  '--properties' /** propertiesToConsider */,
@@ -32,6 +32,7 @@ const path = __importStar(require("path"));
32
32
  const vm = __importStar(require("vm"));
33
33
  const paths_1 = require("./ivy/paths");
34
34
  const inline_resource_1 = require("./loaders/inline-resource");
35
+ const replace_resources_1 = require("./transformers/replace_resources");
35
36
  class WebpackResourceLoader {
36
37
  constructor(shouldCache) {
37
38
  this._fileDependencies = new Map();
@@ -93,15 +94,23 @@ class WebpackResourceLoader {
93
94
  if (!this._parentCompilation) {
94
95
  throw new Error('WebpackResourceLoader cannot be used without parentCompilation');
95
96
  }
96
- // Create a special URL for reading the resource from memory
97
- const entry = filePath ||
98
- (resourceType
99
- ? `${containingFile}-${this.outputPathCounter}.${fileExtension}!=!${this.inlineDataLoaderPath}!${containingFile}`
100
- : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
101
- `angular-resource:${resourceType},${(0, crypto_1.createHash)('md5').update(data).digest('hex')}`);
102
- if (!entry) {
103
- throw new Error(`"filePath" or "data" must be specified.`);
104
- }
97
+ const getEntry = () => {
98
+ if (filePath) {
99
+ return `${filePath}?${replace_resources_1.NG_COMPONENT_RESOURCE_QUERY}`;
100
+ }
101
+ else if (resourceType) {
102
+ return (
103
+ // app.component.ts-2.css?ngResource!=!@ngtools/webpack/src/loaders/inline-resource.js!app.component.ts
104
+ `${containingFile}-${this.outputPathCounter}.${fileExtension}` +
105
+ `?${replace_resources_1.NG_COMPONENT_RESOURCE_QUERY}!=!${this.inlineDataLoaderPath}!${containingFile}`);
106
+ }
107
+ else if (data) {
108
+ // Create a special URL for reading the resource from memory
109
+ return `angular-resource:${resourceType},${(0, crypto_1.createHash)('md5').update(data).digest('hex')}`;
110
+ }
111
+ throw new Error(`"filePath", "resourceType" or "data" must be specified.`);
112
+ };
113
+ const entry = getEntry();
105
114
  // Simple sanity check.
106
115
  if (filePath === null || filePath === void 0 ? void 0 : filePath.match(/\.[jt]s$/)) {
107
116
  throw new Error(`Cannot use a JavaScript or TypeScript file (${filePath}) in a component's styleUrls or templateUrl.`);
@@ -162,8 +171,11 @@ class WebpackResourceLoader {
162
171
  childCompilation.hooks.processAssets.tap({ name: 'angular-compiler', stage: webpack.Compilation.PROCESS_ASSETS_STAGE_REPORT }, () => {
163
172
  var _a;
164
173
  finalContent = (_a = childCompilation.assets[outputFilePath]) === null || _a === void 0 ? void 0 : _a.source().toString();
165
- delete childCompilation.assets[outputFilePath];
166
- delete childCompilation.assets[outputFilePath + '.map'];
174
+ for (const { files } of childCompilation.chunks) {
175
+ for (const file of files) {
176
+ childCompilation.deleteAsset(file);
177
+ }
178
+ }
167
179
  });
168
180
  });
169
181
  return new Promise((resolve, reject) => {
@@ -6,5 +6,6 @@
6
6
  * found in the LICENSE file at https://angular.io/license
7
7
  */
8
8
  import * as ts from 'typescript';
9
- export declare function replaceResources(shouldTransform: (fileName: string) => boolean, getTypeChecker: () => ts.TypeChecker, directTemplateLoading?: boolean, inlineStyleFileExtension?: string): ts.TransformerFactory<ts.SourceFile>;
10
- export declare function getResourceUrl(node: ts.Node, loader?: string): string | null;
9
+ export declare const NG_COMPONENT_RESOURCE_QUERY = "ngResource";
10
+ export declare function replaceResources(shouldTransform: (fileName: string) => boolean, getTypeChecker: () => ts.TypeChecker, inlineStyleFileExtension?: string): ts.TransformerFactory<ts.SourceFile>;
11
+ export declare function getResourceUrl(node: ts.Node): string | null;
@@ -26,11 +26,11 @@ var __importStar = (this && this.__importStar) || function (mod) {
26
26
  return result;
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.getResourceUrl = exports.replaceResources = void 0;
29
+ exports.getResourceUrl = exports.replaceResources = exports.NG_COMPONENT_RESOURCE_QUERY = void 0;
30
30
  const ts = __importStar(require("typescript"));
31
- const direct_resource_1 = require("../loaders/direct-resource");
32
31
  const inline_resource_1 = require("../loaders/inline-resource");
33
- function replaceResources(shouldTransform, getTypeChecker, directTemplateLoading = false, inlineStyleFileExtension) {
32
+ exports.NG_COMPONENT_RESOURCE_QUERY = 'ngResource';
33
+ function replaceResources(shouldTransform, getTypeChecker, inlineStyleFileExtension) {
34
34
  return (context) => {
35
35
  const typeChecker = getTypeChecker();
36
36
  const resourceImportDeclarations = [];
@@ -39,7 +39,7 @@ function replaceResources(shouldTransform, getTypeChecker, directTemplateLoading
39
39
  const visitNode = (node) => {
40
40
  if (ts.isClassDeclaration(node)) {
41
41
  const decorators = ts.visitNodes(node.decorators, (node) => ts.isDecorator(node)
42
- ? visitDecorator(nodeFactory, node, typeChecker, directTemplateLoading, resourceImportDeclarations, moduleKind, inlineStyleFileExtension)
42
+ ? visitDecorator(nodeFactory, node, typeChecker, resourceImportDeclarations, moduleKind, inlineStyleFileExtension)
43
43
  : node);
44
44
  return nodeFactory.updateClassDeclaration(node, decorators, node.modifiers, node.name, node.typeParameters, node.heritageClauses, node.members);
45
45
  }
@@ -62,7 +62,7 @@ function replaceResources(shouldTransform, getTypeChecker, directTemplateLoading
62
62
  };
63
63
  }
64
64
  exports.replaceResources = replaceResources;
65
- function visitDecorator(nodeFactory, node, typeChecker, directTemplateLoading, resourceImportDeclarations, moduleKind, inlineStyleFileExtension) {
65
+ function visitDecorator(nodeFactory, node, typeChecker, resourceImportDeclarations, moduleKind, inlineStyleFileExtension) {
66
66
  if (!isComponentDecorator(node, typeChecker)) {
67
67
  return node;
68
68
  }
@@ -79,7 +79,7 @@ function visitDecorator(nodeFactory, node, typeChecker, directTemplateLoading, r
79
79
  const styleReplacements = [];
80
80
  // visit all properties
81
81
  let properties = ts.visitNodes(objectExpression.properties, (node) => ts.isObjectLiteralElementLike(node)
82
- ? visitComponentMetadata(nodeFactory, node, styleReplacements, directTemplateLoading, resourceImportDeclarations, moduleKind, inlineStyleFileExtension)
82
+ ? visitComponentMetadata(nodeFactory, node, styleReplacements, resourceImportDeclarations, moduleKind, inlineStyleFileExtension)
83
83
  : node);
84
84
  // replace properties with updated properties
85
85
  if (styleReplacements.length > 0) {
@@ -88,7 +88,7 @@ function visitDecorator(nodeFactory, node, typeChecker, directTemplateLoading, r
88
88
  }
89
89
  return nodeFactory.updateDecorator(node, nodeFactory.updateCallExpression(decoratorFactory, decoratorFactory.expression, decoratorFactory.typeArguments, [nodeFactory.updateObjectLiteralExpression(objectExpression, properties)]));
90
90
  }
91
- function visitComponentMetadata(nodeFactory, node, styleReplacements, directTemplateLoading, resourceImportDeclarations, moduleKind, inlineStyleFileExtension) {
91
+ function visitComponentMetadata(nodeFactory, node, styleReplacements, resourceImportDeclarations, moduleKind = ts.ModuleKind.ES2015, inlineStyleFileExtension) {
92
92
  if (!ts.isPropertyAssignment(node) || ts.isComputedPropertyName(node.name)) {
93
93
  return node;
94
94
  }
@@ -97,7 +97,7 @@ function visitComponentMetadata(nodeFactory, node, styleReplacements, directTemp
97
97
  case 'moduleId':
98
98
  return undefined;
99
99
  case 'templateUrl':
100
- const url = getResourceUrl(node.initializer, directTemplateLoading ? `!${direct_resource_1.DirectAngularResourceLoaderPath}!` : '');
100
+ const url = getResourceUrl(node.initializer);
101
101
  if (!url) {
102
102
  return node;
103
103
  }
@@ -121,7 +121,10 @@ function visitComponentMetadata(nodeFactory, node, styleReplacements, directTemp
121
121
  if (inlineStyleFileExtension) {
122
122
  const data = Buffer.from(node.text).toString('base64');
123
123
  const containingFile = node.getSourceFile().fileName;
124
- url = `${containingFile}.${inlineStyleFileExtension}!=!${inline_resource_1.InlineAngularResourceLoaderPath}?data=${encodeURIComponent(data)}!${containingFile}`;
124
+ // app.component.ts.css?ngResource!=!@ngtools/webpack/src/loaders/inline-resource.js?data=...!app.component.ts
125
+ url =
126
+ `${containingFile}.${inlineStyleFileExtension}?${exports.NG_COMPONENT_RESOURCE_QUERY}` +
127
+ `!=!${inline_resource_1.InlineAngularResourceLoaderPath}?data=${encodeURIComponent(data)}!${containingFile}`;
125
128
  }
126
129
  else {
127
130
  return nodeFactory.createStringLiteral(node.text);
@@ -147,12 +150,12 @@ function visitComponentMetadata(nodeFactory, node, styleReplacements, directTemp
147
150
  return node;
148
151
  }
149
152
  }
150
- function getResourceUrl(node, loader = '') {
153
+ function getResourceUrl(node) {
151
154
  // only analyze strings
152
155
  if (!ts.isStringLiteral(node) && !ts.isNoSubstitutionTemplateLiteral(node)) {
153
156
  return null;
154
157
  }
155
- return `${loader}${/^\.?\.\//.test(node.text) ? '' : './'}${node.text}`;
158
+ return `${/^\.?\.\//.test(node.text) ? '' : './'}${node.text}?${exports.NG_COMPONENT_RESOURCE_QUERY}`;
156
159
  }
157
160
  exports.getResourceUrl = getResourceUrl;
158
161
  function isComponentDecorator(node, typeChecker) {
@@ -165,10 +168,10 @@ function isComponentDecorator(node, typeChecker) {
165
168
  }
166
169
  return false;
167
170
  }
168
- function createResourceImport(nodeFactory, url, resourceImportDeclarations, moduleKind = ts.ModuleKind.ES2015) {
171
+ function createResourceImport(nodeFactory, url, resourceImportDeclarations, moduleKind) {
169
172
  const urlLiteral = nodeFactory.createStringLiteral(url);
170
173
  if (moduleKind < ts.ModuleKind.ES2015) {
171
- return nodeFactory.createPropertyAccessExpression(nodeFactory.createCallExpression(nodeFactory.createIdentifier('require'), [], [urlLiteral]), 'default');
174
+ return nodeFactory.createCallExpression(nodeFactory.createIdentifier('require'), [], [urlLiteral]);
172
175
  }
173
176
  else {
174
177
  const importName = nodeFactory.createIdentifier(`__NG_CLI_RESOURCE__${resourceImportDeclarations.length}`);
@@ -1,9 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright Google LLC All Rights Reserved.
4
- *
5
- * Use of this source code is governed by an MIT-style license that can be
6
- * found in the LICENSE file at https://angular.io/license
7
- */
8
- export declare const DirectAngularResourceLoaderPath: string;
9
- export default function (content: string): string;
@@ -1,15 +0,0 @@
1
- "use strict";
2
- /**
3
- * @license
4
- * Copyright Google LLC All Rights Reserved.
5
- *
6
- * Use of this source code is governed by an MIT-style license that can be
7
- * found in the LICENSE file at https://angular.io/license
8
- */
9
- Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.DirectAngularResourceLoaderPath = void 0;
11
- exports.DirectAngularResourceLoaderPath = __filename;
12
- function default_1(content) {
13
- return `export default ${JSON.stringify(content)};`;
14
- }
15
- exports.default = default_1;