@angular-devkit/build-angular 17.1.2 → 17.2.0-next.1

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.
Files changed (51) hide show
  1. package/package.json +31 -32
  2. package/src/builders/application/build-action.js +0 -4
  3. package/src/builders/application/execute-build.js +8 -15
  4. package/src/builders/application/index.js +19 -3
  5. package/src/builders/application/options.d.ts +3 -0
  6. package/src/builders/application/options.js +12 -1
  7. package/src/builders/application/setup-bundling.js +2 -2
  8. package/src/builders/dev-server/options.js +3 -2
  9. package/src/builders/dev-server/schema.json +1 -1
  10. package/src/builders/extract-i18n/options.js +3 -2
  11. package/src/builders/extract-i18n/schema.json +1 -1
  12. package/src/builders/jest/index.js +44 -5
  13. package/src/builders/jest/jest.config.mjs +11 -0
  14. package/src/tools/babel/plugins/elide-angular-metadata.d.ts +1 -1
  15. package/src/tools/babel/plugins/elide-angular-metadata.js +38 -30
  16. package/src/tools/babel/plugins/pure-toplevel-functions.d.ts +1 -1
  17. package/src/tools/babel/plugins/pure-toplevel-functions.js +3 -4
  18. package/src/tools/esbuild/angular/compilation/angular-compilation.d.ts +9 -2
  19. package/src/tools/esbuild/angular/compilation/angular-compilation.js +11 -3
  20. package/src/tools/esbuild/angular/compilation/aot-compilation.d.ts +2 -2
  21. package/src/tools/esbuild/angular/compilation/aot-compilation.js +19 -8
  22. package/src/tools/esbuild/angular/compilation/index.d.ts +1 -1
  23. package/src/tools/esbuild/angular/compilation/index.js +2 -1
  24. package/src/tools/esbuild/angular/compilation/jit-compilation.d.ts +2 -2
  25. package/src/tools/esbuild/angular/compilation/jit-compilation.js +12 -6
  26. package/src/tools/esbuild/angular/compilation/parallel-compilation.d.ts +2 -2
  27. package/src/tools/esbuild/angular/compilation/parallel-compilation.js +2 -2
  28. package/src/tools/esbuild/angular/compilation/parallel-worker.d.ts +2 -1
  29. package/src/tools/esbuild/angular/compilation/parallel-worker.js +2 -2
  30. package/src/tools/esbuild/angular/compiler-plugin.js +7 -7
  31. package/src/tools/esbuild/application-code-bundle.js +2 -2
  32. package/src/tools/esbuild/budget-stats.js +5 -0
  33. package/src/tools/esbuild/bundler-context.js +6 -0
  34. package/src/tools/esbuild/bundler-execution-result.d.ts +2 -0
  35. package/src/tools/esbuild/bundler-execution-result.js +6 -0
  36. package/src/tools/esbuild/compiler-plugin-options.js +2 -1
  37. package/src/tools/esbuild/global-scripts.js +3 -4
  38. package/src/tools/esbuild/global-styles.js +2 -1
  39. package/src/tools/esbuild/stylesheets/bundle-options.d.ts +2 -0
  40. package/src/tools/esbuild/stylesheets/bundle-options.js +1 -0
  41. package/src/tools/esbuild/stylesheets/stylesheet-plugin-factory.d.ts +7 -0
  42. package/src/tools/esbuild/stylesheets/stylesheet-plugin-factory.js +24 -8
  43. package/src/tools/esbuild/utils.d.ts +5 -8
  44. package/src/tools/esbuild/utils.js +64 -31
  45. package/src/tools/vite/angular-memory-plugin.js +6 -5
  46. package/src/tools/webpack/utils/stats.d.ts +1 -0
  47. package/src/tools/webpack/utils/stats.js +98 -47
  48. package/src/utils/environment-options.d.ts +2 -0
  49. package/src/utils/environment-options.js +5 -1
  50. package/src/utils/postcss-configuration.d.ts +11 -0
  51. package/src/utils/postcss-configuration.js +77 -0
@@ -14,6 +14,13 @@ export interface EmitFileResult {
14
14
  contents: string;
15
15
  dependencies?: readonly string[];
16
16
  }
17
+ export declare enum DiagnosticModes {
18
+ None = 0,
19
+ Option = 1,
20
+ Syntactic = 2,
21
+ Semantic = 4,
22
+ All = 7
23
+ }
17
24
  export declare abstract class AngularCompilation {
18
25
  #private;
19
26
  static loadCompilerCli(): Promise<typeof ng>;
@@ -25,8 +32,8 @@ export declare abstract class AngularCompilation {
25
32
  referencedFiles: readonly string[];
26
33
  }>;
27
34
  abstract emitAffectedFiles(): Iterable<EmitFileResult> | Promise<Iterable<EmitFileResult>>;
28
- protected abstract collectDiagnostics(): Iterable<ts.Diagnostic> | Promise<Iterable<ts.Diagnostic>>;
29
- diagnoseFiles(): Promise<{
35
+ protected abstract collectDiagnostics(modes: DiagnosticModes): Iterable<ts.Diagnostic> | Promise<Iterable<ts.Diagnostic>>;
36
+ diagnoseFiles(modes?: DiagnosticModes): Promise<{
30
37
  errors?: PartialMessage[];
31
38
  warnings?: PartialMessage[];
32
39
  }>;
@@ -30,10 +30,18 @@ var __importStar = (this && this.__importStar) || function (mod) {
30
30
  return result;
31
31
  };
32
32
  Object.defineProperty(exports, "__esModule", { value: true });
33
- exports.AngularCompilation = void 0;
33
+ exports.AngularCompilation = exports.DiagnosticModes = void 0;
34
34
  const load_esm_1 = require("../../../../utils/load-esm");
35
35
  const profiling_1 = require("../../profiling");
36
36
  const diagnostics_1 = require("../diagnostics");
37
+ var DiagnosticModes;
38
+ (function (DiagnosticModes) {
39
+ DiagnosticModes[DiagnosticModes["None"] = 0] = "None";
40
+ DiagnosticModes[DiagnosticModes["Option"] = 1] = "Option";
41
+ DiagnosticModes[DiagnosticModes["Syntactic"] = 2] = "Syntactic";
42
+ DiagnosticModes[DiagnosticModes["Semantic"] = 4] = "Semantic";
43
+ DiagnosticModes[DiagnosticModes["All"] = 7] = "All";
44
+ })(DiagnosticModes || (exports.DiagnosticModes = DiagnosticModes = {}));
37
45
  class AngularCompilation {
38
46
  static #angularCompilerCliModule;
39
47
  static #typescriptModule;
@@ -64,13 +72,13 @@ class AngularCompilation {
64
72
  supportJitMode: false,
65
73
  }));
66
74
  }
67
- async diagnoseFiles() {
75
+ async diagnoseFiles(modes = DiagnosticModes.All) {
68
76
  const result = {};
69
77
  // Avoid loading typescript until actually needed.
70
78
  // This allows for avoiding the load of typescript in the main thread when using the parallel compilation.
71
79
  const typescript = await AngularCompilation.loadTypescript();
72
80
  await (0, profiling_1.profileAsync)('NG_DIAGNOSTICS_TOTAL', async () => {
73
- for (const diagnostic of await this.collectDiagnostics()) {
81
+ for (const diagnostic of await this.collectDiagnostics(modes)) {
74
82
  const message = (0, diagnostics_1.convertTypeScriptDiagnostic)(typescript, diagnostic);
75
83
  if (diagnostic.category === typescript.DiagnosticCategory.Error) {
76
84
  (result.errors ??= []).push(message);
@@ -8,7 +8,7 @@
8
8
  import type ng from '@angular/compiler-cli';
9
9
  import ts from 'typescript';
10
10
  import { AngularHostOptions } from '../angular-host';
11
- import { AngularCompilation, EmitFileResult } from './angular-compilation';
11
+ import { AngularCompilation, DiagnosticModes, EmitFileResult } from './angular-compilation';
12
12
  export declare class AotCompilation extends AngularCompilation {
13
13
  #private;
14
14
  initialize(tsconfig: string, hostOptions: AngularHostOptions, compilerOptionsTransformer?: (compilerOptions: ng.CompilerOptions) => ng.CompilerOptions): Promise<{
@@ -16,6 +16,6 @@ export declare class AotCompilation extends AngularCompilation {
16
16
  compilerOptions: ng.CompilerOptions;
17
17
  referencedFiles: readonly string[];
18
18
  }>;
19
- collectDiagnostics(): Iterable<ts.Diagnostic>;
19
+ collectDiagnostics(modes: DiagnosticModes): Iterable<ts.Diagnostic>;
20
20
  emitAffectedFiles(): Iterable<EmitFileResult>;
21
21
  }
@@ -86,22 +86,33 @@ class AotCompilation extends angular_compilation_1.AngularCompilation {
86
86
  this.#state = new AngularCompilationState(angularProgram, host, typeScriptProgram, affectedFiles, affectedFiles.size === 1 ? OptimizeFor.SingleFile : OptimizeFor.WholeProgram, (0, web_worker_transformer_1.createWorkerTransformer)(hostOptions.processWebWorker.bind(hostOptions)), this.#state?.diagnosticCache);
87
87
  return { affectedFiles, compilerOptions, referencedFiles };
88
88
  }
89
- *collectDiagnostics() {
89
+ *collectDiagnostics(modes) {
90
90
  (0, node_assert_1.default)(this.#state, 'Angular compilation must be initialized prior to collecting diagnostics.');
91
91
  const { affectedFiles, angularCompiler, diagnosticCache, templateDiagnosticsOptimization, typeScriptProgram, } = this.#state;
92
+ const syntactic = modes & angular_compilation_1.DiagnosticModes.Syntactic;
93
+ const semantic = modes & angular_compilation_1.DiagnosticModes.Semantic;
92
94
  // Collect program level diagnostics
93
- yield* typeScriptProgram.getConfigFileParsingDiagnostics();
94
- yield* angularCompiler.getOptionDiagnostics();
95
- yield* typeScriptProgram.getOptionsDiagnostics();
96
- yield* typeScriptProgram.getGlobalDiagnostics();
95
+ if (modes & angular_compilation_1.DiagnosticModes.Option) {
96
+ yield* typeScriptProgram.getConfigFileParsingDiagnostics();
97
+ yield* angularCompiler.getOptionDiagnostics();
98
+ yield* typeScriptProgram.getOptionsDiagnostics();
99
+ }
100
+ if (syntactic) {
101
+ yield* typeScriptProgram.getGlobalDiagnostics();
102
+ }
97
103
  // Collect source file specific diagnostics
98
104
  for (const sourceFile of typeScriptProgram.getSourceFiles()) {
99
105
  if (angularCompiler.ignoreForDiagnostics.has(sourceFile)) {
100
106
  continue;
101
107
  }
102
- // TypeScript will use cached diagnostics for files that have not been
103
- // changed or affected for this build when using incremental building.
104
- yield* (0, profiling_1.profileSync)('NG_DIAGNOSTICS_SYNTACTIC', () => typeScriptProgram.getSyntacticDiagnostics(sourceFile), true);
108
+ if (syntactic) {
109
+ // TypeScript will use cached diagnostics for files that have not been
110
+ // changed or affected for this build when using incremental building.
111
+ yield* (0, profiling_1.profileSync)('NG_DIAGNOSTICS_SYNTACTIC', () => typeScriptProgram.getSyntacticDiagnostics(sourceFile), true);
112
+ }
113
+ if (!semantic) {
114
+ continue;
115
+ }
105
116
  yield* (0, profiling_1.profileSync)('NG_DIAGNOSTICS_SEMANTIC', () => typeScriptProgram.getSemanticDiagnostics(sourceFile), true);
106
117
  // Declaration files cannot have template diagnostics
107
118
  if (sourceFile.isDeclarationFile) {
@@ -5,6 +5,6 @@
5
5
  * Use of this source code is governed by an MIT-style license that can be
6
6
  * found in the LICENSE file at https://angular.io/license
7
7
  */
8
- export { AngularCompilation } from './angular-compilation';
8
+ export { AngularCompilation, DiagnosticModes } from './angular-compilation';
9
9
  export { createAngularCompilation } from './factory';
10
10
  export { NoopCompilation } from './noop-compilation';
@@ -7,9 +7,10 @@
7
7
  * found in the LICENSE file at https://angular.io/license
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.NoopCompilation = exports.createAngularCompilation = exports.AngularCompilation = void 0;
10
+ exports.NoopCompilation = exports.createAngularCompilation = exports.DiagnosticModes = exports.AngularCompilation = void 0;
11
11
  var angular_compilation_1 = require("./angular-compilation");
12
12
  Object.defineProperty(exports, "AngularCompilation", { enumerable: true, get: function () { return angular_compilation_1.AngularCompilation; } });
13
+ Object.defineProperty(exports, "DiagnosticModes", { enumerable: true, get: function () { return angular_compilation_1.DiagnosticModes; } });
13
14
  var factory_1 = require("./factory");
14
15
  Object.defineProperty(exports, "createAngularCompilation", { enumerable: true, get: function () { return factory_1.createAngularCompilation; } });
15
16
  var noop_compilation_1 = require("./noop-compilation");
@@ -8,7 +8,7 @@
8
8
  import type ng from '@angular/compiler-cli';
9
9
  import ts from 'typescript';
10
10
  import { AngularHostOptions } from '../angular-host';
11
- import { AngularCompilation, EmitFileResult } from './angular-compilation';
11
+ import { AngularCompilation, DiagnosticModes, EmitFileResult } from './angular-compilation';
12
12
  export declare class JitCompilation extends AngularCompilation {
13
13
  #private;
14
14
  initialize(tsconfig: string, hostOptions: AngularHostOptions, compilerOptionsTransformer?: (compilerOptions: ng.CompilerOptions) => ng.CompilerOptions): Promise<{
@@ -16,6 +16,6 @@ export declare class JitCompilation extends AngularCompilation {
16
16
  compilerOptions: ng.CompilerOptions;
17
17
  referencedFiles: readonly string[];
18
18
  }>;
19
- collectDiagnostics(): Iterable<ts.Diagnostic>;
19
+ collectDiagnostics(modes: DiagnosticModes): Iterable<ts.Diagnostic>;
20
20
  emitAffectedFiles(): Iterable<EmitFileResult>;
21
21
  }
@@ -51,15 +51,21 @@ class JitCompilation extends angular_compilation_1.AngularCompilation {
51
51
  .map((sourceFile) => sourceFile.fileName);
52
52
  return { affectedFiles, compilerOptions, referencedFiles };
53
53
  }
54
- *collectDiagnostics() {
54
+ *collectDiagnostics(modes) {
55
55
  (0, node_assert_1.default)(this.#state, 'Compilation must be initialized prior to collecting diagnostics.');
56
56
  const { typeScriptProgram } = this.#state;
57
57
  // Collect program level diagnostics
58
- yield* typeScriptProgram.getConfigFileParsingDiagnostics();
59
- yield* typeScriptProgram.getOptionsDiagnostics();
60
- yield* typeScriptProgram.getGlobalDiagnostics();
61
- yield* (0, profiling_1.profileSync)('NG_DIAGNOSTICS_SYNTACTIC', () => typeScriptProgram.getSyntacticDiagnostics());
62
- yield* (0, profiling_1.profileSync)('NG_DIAGNOSTICS_SEMANTIC', () => typeScriptProgram.getSemanticDiagnostics());
58
+ if (modes & angular_compilation_1.DiagnosticModes.Option) {
59
+ yield* typeScriptProgram.getConfigFileParsingDiagnostics();
60
+ yield* typeScriptProgram.getOptionsDiagnostics();
61
+ }
62
+ if (modes & angular_compilation_1.DiagnosticModes.Syntactic) {
63
+ yield* typeScriptProgram.getGlobalDiagnostics();
64
+ yield* (0, profiling_1.profileSync)('NG_DIAGNOSTICS_SYNTACTIC', () => typeScriptProgram.getSyntacticDiagnostics());
65
+ }
66
+ if (modes & angular_compilation_1.DiagnosticModes.Semantic) {
67
+ yield* (0, profiling_1.profileSync)('NG_DIAGNOSTICS_SEMANTIC', () => typeScriptProgram.getSemanticDiagnostics());
68
+ }
63
69
  }
64
70
  emitAffectedFiles() {
65
71
  (0, node_assert_1.default)(this.#state, 'Compilation must be initialized prior to emitting files.');
@@ -9,7 +9,7 @@ import type { CompilerOptions } from '@angular/compiler-cli';
9
9
  import type { PartialMessage } from 'esbuild';
10
10
  import type { SourceFile } from 'typescript';
11
11
  import type { AngularHostOptions } from '../angular-host';
12
- import { AngularCompilation, EmitFileResult } from './angular-compilation';
12
+ import { AngularCompilation, DiagnosticModes, EmitFileResult } from './angular-compilation';
13
13
  /**
14
14
  * An Angular compilation which uses a Node.js Worker thread to load and execute
15
15
  * the TypeScript and Angular compilers. This allows for longer synchronous actions
@@ -32,7 +32,7 @@ export declare class ParallelCompilation extends AngularCompilation {
32
32
  * with the serializable esbuild compatible diagnostics.
33
33
  */
34
34
  protected collectDiagnostics(): never;
35
- diagnoseFiles(): Promise<{
35
+ diagnoseFiles(modes?: DiagnosticModes): Promise<{
36
36
  errors?: PartialMessage[];
37
37
  warnings?: PartialMessage[];
38
38
  }>;
@@ -106,8 +106,8 @@ class ParallelCompilation extends angular_compilation_1.AngularCompilation {
106
106
  collectDiagnostics() {
107
107
  throw new Error('Not implemented in ParallelCompilation.');
108
108
  }
109
- diagnoseFiles() {
110
- return this.#worker.run(undefined, { name: 'diagnose' });
109
+ diagnoseFiles(modes = angular_compilation_1.DiagnosticModes.All) {
110
+ return this.#worker.run(modes, { name: 'diagnose' });
111
111
  }
112
112
  emitAffectedFiles() {
113
113
  return this.#worker.run(undefined, { name: 'emit' });
@@ -10,6 +10,7 @@
10
10
  /// <reference types="@types/node/ts4.8/worker_threads" />
11
11
  import type { PartialMessage } from 'esbuild';
12
12
  import { type MessagePort } from 'node:worker_threads';
13
+ import type { DiagnosticModes } from './angular-compilation';
13
14
  export interface InitRequest {
14
15
  jit: boolean;
15
16
  tsconfig: string;
@@ -26,7 +27,7 @@ export declare function initialize(request: InitRequest): Promise<{
26
27
  allowJs: boolean | undefined;
27
28
  };
28
29
  }>;
29
- export declare function diagnose(): Promise<{
30
+ export declare function diagnose(modes: DiagnosticModes): Promise<{
30
31
  errors?: PartialMessage[];
31
32
  warnings?: PartialMessage[];
32
33
  }>;
@@ -72,9 +72,9 @@ async function initialize(request) {
72
72
  };
73
73
  }
74
74
  exports.initialize = initialize;
75
- async function diagnose() {
75
+ async function diagnose(modes) {
76
76
  (0, node_assert_1.default)(compilation);
77
- const diagnostics = await compilation.diagnoseFiles();
77
+ const diagnostics = await compilation.diagnoseFiles(modes);
78
78
  return diagnostics;
79
79
  }
80
80
  exports.diagnose = diagnose;
@@ -195,13 +195,6 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
195
195
  hasCompilationErrors = await sharedTSCompilationState.waitUntilReady;
196
196
  return result;
197
197
  }
198
- const diagnostics = await compilation.diagnoseFiles();
199
- if (diagnostics.errors?.length) {
200
- (result.errors ??= []).push(...diagnostics.errors);
201
- }
202
- if (diagnostics.warnings?.length) {
203
- (result.warnings ??= []).push(...diagnostics.warnings);
204
- }
205
198
  // Update TypeScript file output cache for all affected files
206
199
  try {
207
200
  await (0, profiling_1.profileAsync)('NG_EMIT_TS', async () => {
@@ -222,6 +215,13 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
222
215
  ],
223
216
  });
224
217
  }
218
+ const diagnostics = await compilation.diagnoseFiles(environment_options_1.useTypeChecking ? compilation_1.DiagnosticModes.All : compilation_1.DiagnosticModes.All & ~compilation_1.DiagnosticModes.Semantic);
219
+ if (diagnostics.errors?.length) {
220
+ (result.errors ??= []).push(...diagnostics.errors);
221
+ }
222
+ if (diagnostics.warnings?.length) {
223
+ (result.warnings ??= []).push(...diagnostics.warnings);
224
+ }
225
225
  // Add errors from failed additional results.
226
226
  // This must be done after emit to capture latest web worker results.
227
227
  for (const { errors } of additionalResults.values()) {
@@ -230,7 +230,7 @@ function createServerPolyfillBundleOptions(options, target, sourceFileCache) {
230
230
  }
231
231
  exports.createServerPolyfillBundleOptions = createServerPolyfillBundleOptions;
232
232
  function getEsBuildCommonOptions(options) {
233
- const { workspaceRoot, outExtension, optimizationOptions, sourcemapOptions, tsconfig, externalDependencies, outputNames, preserveSymlinks, jit, loaderExtensions, } = options;
233
+ const { workspaceRoot, outExtension, optimizationOptions, sourcemapOptions, tsconfig, externalDependencies, outputNames, preserveSymlinks, jit, loaderExtensions, jsonLogs, } = options;
234
234
  // Ensure unique hashes for i18n translation changes when using post-process inlining.
235
235
  // This hash value is added as a footer to each file and ensures that the output file names (with hashes)
236
236
  // change when translation files have changed. If this is not done the post processed files may have
@@ -250,7 +250,7 @@ function getEsBuildCommonOptions(options) {
250
250
  resolveExtensions: ['.ts', '.tsx', '.mjs', '.js'],
251
251
  metafile: true,
252
252
  legalComments: options.extractLicenses ? 'none' : 'eof',
253
- logLevel: options.verbose ? 'debug' : 'silent',
253
+ logLevel: options.verbose && !jsonLogs ? 'debug' : 'silent',
254
254
  minifyIdentifiers: optimizationOptions.scripts && environment_options_1.allowMangle,
255
255
  minifySyntax: optimizationOptions.scripts,
256
256
  minifyWhitespace: optimizationOptions.scripts,
@@ -26,6 +26,11 @@ function generateBudgetStats(metafile, initialFiles) {
26
26
  if (!file.endsWith('.js') && !file.endsWith('.css')) {
27
27
  continue;
28
28
  }
29
+ // Exclude server bundles
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
+ if (entry['ng-platform-server']) {
32
+ continue;
33
+ }
29
34
  const initialRecord = initialFiles.get(file);
30
35
  let name = initialRecord?.name;
31
36
  if (name === undefined && entry.entryPoint) {
@@ -162,6 +162,12 @@ class BundlerContext {
162
162
  // For non-incremental builds, perform a single build
163
163
  result = await (0, esbuild_1.build)(this.#esbuildOptions);
164
164
  }
165
+ if (this.#esbuildOptions?.platform === 'node') {
166
+ for (const entry of Object.values(result.metafile.outputs)) {
167
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
168
+ entry['ng-platform-server'] = true;
169
+ }
170
+ }
165
171
  }
166
172
  catch (failure) {
167
173
  // Build failures will throw an exception which contains errors/warnings
@@ -33,6 +33,7 @@ export declare class ExecutionResult {
33
33
  outputFiles: BuildOutputFile[];
34
34
  assetFiles: BuildOutputAsset[];
35
35
  errors: (Message | PartialMessage)[];
36
+ prerenderedRoutes: string[];
36
37
  warnings: (Message | PartialMessage)[];
37
38
  externalMetadata?: ExternalResultMetadata;
38
39
  constructor(rebuildContexts: BundlerContext[], codeBundleCache?: SourceFileCache | undefined);
@@ -40,6 +41,7 @@ export declare class ExecutionResult {
40
41
  addAssets(assets: BuildOutputAsset[]): void;
41
42
  addError(error: PartialMessage | string): void;
42
43
  addErrors(errors: (PartialMessage | string)[]): void;
44
+ addPrerenderedRoutes(routes: string[]): void;
43
45
  addWarning(error: PartialMessage | string): void;
44
46
  addWarnings(errors: (PartialMessage | string)[]): void;
45
47
  /**
@@ -19,6 +19,7 @@ class ExecutionResult {
19
19
  outputFiles = [];
20
20
  assetFiles = [];
21
21
  errors = [];
22
+ prerenderedRoutes = [];
22
23
  warnings = [];
23
24
  externalMetadata;
24
25
  constructor(rebuildContexts, codeBundleCache) {
@@ -44,6 +45,11 @@ class ExecutionResult {
44
45
  this.addError(error);
45
46
  }
46
47
  }
48
+ addPrerenderedRoutes(routes) {
49
+ this.prerenderedRoutes.push(...routes);
50
+ // Sort the prerendered routes.
51
+ this.prerenderedRoutes.sort((a, b) => a.localeCompare(b));
52
+ }
47
53
  addWarning(error) {
48
54
  if (typeof error === 'string') {
49
55
  this.warnings.push({ text: error, location: null });
@@ -9,7 +9,7 @@
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.createCompilerPluginOptions = void 0;
11
11
  function createCompilerPluginOptions(options, target, sourceFileCache) {
12
- const { workspaceRoot, optimizationOptions, sourcemapOptions, tsconfig, outputNames, fileReplacements, externalDependencies, preserveSymlinks, stylePreprocessorOptions, advancedOptimizations, inlineStyleLanguage, jit, cacheOptions, tailwindConfiguration, publicPath, } = options;
12
+ const { workspaceRoot, optimizationOptions, sourcemapOptions, tsconfig, outputNames, fileReplacements, externalDependencies, preserveSymlinks, stylePreprocessorOptions, advancedOptimizations, inlineStyleLanguage, jit, cacheOptions, tailwindConfiguration, postcssConfiguration, publicPath, } = options;
13
13
  return {
14
14
  // JS/TS options
15
15
  pluginOptions: {
@@ -40,6 +40,7 @@ function createCompilerPluginOptions(options, target, sourceFileCache) {
40
40
  inlineStyleLanguage,
41
41
  preserveSymlinks,
42
42
  tailwindConfiguration,
43
+ postcssConfiguration,
43
44
  cacheOptions,
44
45
  publicPath,
45
46
  },
@@ -49,7 +49,7 @@ const virtual_module_plugin_1 = require("./virtual-module-plugin");
49
49
  * @returns An esbuild BuildOptions object.
50
50
  */
51
51
  function createGlobalScriptsBundleOptions(options, target, initial) {
52
- const { globalScripts, optimizationOptions, outputNames, preserveSymlinks, sourcemapOptions, workspaceRoot, } = options;
52
+ const { globalScripts, optimizationOptions, outputNames, preserveSymlinks, sourcemapOptions, jsonLogs, workspaceRoot, } = options;
53
53
  const namespace = 'angular:script/global';
54
54
  const entryPoints = {};
55
55
  let found = false;
@@ -74,7 +74,7 @@ function createGlobalScriptsBundleOptions(options, target, initial) {
74
74
  mainFields: ['script', 'browser', 'main'],
75
75
  conditions: ['script'],
76
76
  resolveExtensions: ['.mjs', '.js'],
77
- logLevel: options.verbose ? 'debug' : 'silent',
77
+ logLevel: options.verbose && !jsonLogs ? 'debug' : 'silent',
78
78
  metafile: true,
79
79
  minify: optimizationOptions.scripts,
80
80
  outdir: workspaceRoot,
@@ -91,8 +91,7 @@ function createGlobalScriptsBundleOptions(options, target, initial) {
91
91
  // Add the `js` extension here so that esbuild generates an output file with the extension
92
92
  transformPath: (path) => path.slice(namespace.length + 1) + '.js',
93
93
  loadContent: (args, build) => (0, load_result_cache_1.createCachedLoad)(loadCache, async (args) => {
94
- const files = globalScripts.find(({ name }) => name === args.path.slice(0, -3))
95
- ?.files;
94
+ const files = globalScripts.find(({ name }) => name === args.path.slice(0, -3))?.files;
96
95
  (0, node_assert_1.default)(files, `Invalid operation: global scripts name not found [${args.path}]`);
97
96
  // Global scripts are concatenated using magic-string instead of bundled via esbuild.
98
97
  const bundleContent = new magic_string_1.Bundle();
@@ -15,7 +15,7 @@ const node_assert_1 = __importDefault(require("node:assert"));
15
15
  const bundle_options_1 = require("./stylesheets/bundle-options");
16
16
  const virtual_module_plugin_1 = require("./virtual-module-plugin");
17
17
  function createGlobalStylesBundleOptions(options, target, initial) {
18
- const { workspaceRoot, optimizationOptions, sourcemapOptions, outputNames, globalStyles, preserveSymlinks, externalDependencies, stylePreprocessorOptions, tailwindConfiguration, cacheOptions, publicPath, } = options;
18
+ const { workspaceRoot, optimizationOptions, sourcemapOptions, outputNames, globalStyles, preserveSymlinks, externalDependencies, stylePreprocessorOptions, tailwindConfiguration, postcssConfiguration, cacheOptions, publicPath, } = options;
19
19
  const namespace = 'angular:styles/global';
20
20
  const entryPoints = {};
21
21
  let found = false;
@@ -46,6 +46,7 @@ function createGlobalStylesBundleOptions(options, target, initial) {
46
46
  },
47
47
  includePaths: stylePreprocessorOptions?.includePaths,
48
48
  tailwindConfiguration,
49
+ postcssConfiguration,
49
50
  cacheOptions,
50
51
  publicPath,
51
52
  }, loadCache);
@@ -7,6 +7,7 @@
7
7
  */
8
8
  import type { BuildOptions } from 'esbuild';
9
9
  import { NormalizedCachedOptions } from '../../../utils/normalize-cache';
10
+ import { PostcssConfiguration } from '../../../utils/postcss-configuration';
10
11
  import { LoadResultCache } from '../load-result-cache';
11
12
  export interface BundleStylesheetOptions {
12
13
  workspaceRoot: string;
@@ -25,6 +26,7 @@ export interface BundleStylesheetOptions {
25
26
  file: string;
26
27
  package: string;
27
28
  };
29
+ postcssConfiguration?: PostcssConfiguration;
28
30
  publicPath?: string;
29
31
  cacheOptions: NormalizedCachedOptions;
30
32
  }
@@ -26,6 +26,7 @@ function createStylesheetBundleOptions(options, cache, inlineComponentData) {
26
26
  includePaths,
27
27
  inlineComponentData,
28
28
  tailwindConfiguration: options.tailwindConfiguration,
29
+ postcssConfiguration: options.postcssConfiguration,
29
30
  }, cache);
30
31
  const plugins = [
31
32
  pluginFactory.create(sass_language_1.SassStylesheetLanguage),
@@ -6,6 +6,7 @@
6
6
  * found in the LICENSE file at https://angular.io/license
7
7
  */
8
8
  import type { OnLoadResult, Plugin, PluginBuild } from 'esbuild';
9
+ import type { PostcssConfiguration } from '../../../utils/postcss-configuration';
9
10
  import { LoadResultCache } from '../load-result-cache';
10
11
  /**
11
12
  * An object containing the plugin options to use when processing stylesheets.
@@ -35,6 +36,12 @@ export interface StylesheetPluginOptions {
35
36
  file: string;
36
37
  package: string;
37
38
  };
39
+ /**
40
+ * Optional configuration object for custom postcss usage. If present, postcss will be
41
+ * initialized and used for every stylesheet. This overrides the tailwind integration
42
+ * and any tailwind usage must be manually configured in the custom postcss usage.
43
+ */
44
+ postcssConfiguration?: PostcssConfiguration;
38
45
  }
39
46
  export interface StylesheetLanguage {
40
47
  name: string;
@@ -72,7 +72,9 @@ class StylesheetPluginFactory {
72
72
  }
73
73
  create(language) {
74
74
  // Return a noop plugin if no load actions are required
75
- if (!language.process && !this.options.tailwindConfiguration) {
75
+ if (!language.process &&
76
+ !this.options.postcssConfiguration &&
77
+ !this.options.tailwindConfiguration) {
76
78
  return {
77
79
  name: 'angular-' + language.name,
78
80
  setup() { },
@@ -84,7 +86,23 @@ class StylesheetPluginFactory {
84
86
  if (this.postcssProcessor) {
85
87
  return this.postcssProcessor;
86
88
  }
87
- if (options.tailwindConfiguration) {
89
+ if (options.postcssConfiguration) {
90
+ const postCssInstanceKey = JSON.stringify(options.postcssConfiguration);
91
+ this.postcssProcessor = postcssProcessor.get(postCssInstanceKey)?.deref();
92
+ if (!this.postcssProcessor) {
93
+ postcss ??= (await Promise.resolve().then(() => __importStar(require('postcss')))).default;
94
+ this.postcssProcessor = postcss();
95
+ for (const [pluginName, pluginOptions] of options.postcssConfiguration.plugins) {
96
+ const { default: plugin } = await Promise.resolve(`${pluginName}`).then(s => __importStar(require(s)));
97
+ if (typeof plugin !== 'function' || plugin.postcss !== true) {
98
+ throw new Error(`Attempted to load invalid Postcss plugin: "${pluginName}"`);
99
+ }
100
+ this.postcssProcessor.use(plugin(pluginOptions));
101
+ }
102
+ postcssProcessor.set(postCssInstanceKey, new WeakRef(this.postcssProcessor));
103
+ }
104
+ }
105
+ else if (options.tailwindConfiguration) {
88
106
  const { package: tailwindPackage, file: config } = options.tailwindConfiguration;
89
107
  const postCssInstanceKey = tailwindPackage + ':' + config;
90
108
  this.postcssProcessor = postcssProcessor.get(postCssInstanceKey)?.deref();
@@ -132,14 +150,12 @@ async function processStylesheet(language, data, filename, format, options, buil
132
150
  watchFiles: [filename],
133
151
  };
134
152
  }
135
- // Return early if there are no contents to further process
136
- if (!result.contents) {
153
+ // Return early if there are no contents to further process or there are errors
154
+ if (!result.contents || result.errors?.length) {
137
155
  return result;
138
156
  }
139
- // Only use postcss if Tailwind processing is required.
140
- // NOTE: If postcss is used for more than just Tailwind in the future this check MUST
141
- // be updated to account for the additional use.
142
- if (postcssProcessor && !result.errors?.length && hasTailwindKeywords(result.contents)) {
157
+ // Only use postcss if Tailwind processing is required or custom postcss is present.
158
+ if (postcssProcessor && (options.postcssConfiguration || hasTailwindKeywords(result.contents))) {
143
159
  const postcssResult = await compileString(typeof result.contents === 'string'
144
160
  ? result.contents
145
161
  : Buffer.from(result.contents).toString('utf-8'), filename, postcssProcessor, options);
@@ -6,19 +6,15 @@
6
6
  * found in the LICENSE file at https://angular.io/license
7
7
  */
8
8
  import { logging } from '@angular-devkit/core';
9
- import { BuildOptions, Metafile, OutputFile, PartialMessage } from 'esbuild';
10
- import { NormalizedOutputOptions } from '../../builders/application/options';
9
+ import { BuildOptions, Metafile, OutputFile } from 'esbuild';
10
+ import { NormalizedApplicationBuildOptions, NormalizedOutputOptions } from '../../builders/application/options';
11
11
  import { BudgetCalculatorResult } from '../../utils/bundle-calculator';
12
12
  import { BuildOutputFile, BuildOutputFileType, InitialFileRecord } from './bundler-context';
13
- import { BuildOutputAsset } from './bundler-execution-result';
14
- export declare function logBuildStats(logger: logging.LoggerApi, metafile: Metafile, initial: Map<string, InitialFileRecord>, budgetFailures: BudgetCalculatorResult[] | undefined, changedFiles?: Set<string>, estimatedTransferSizes?: Map<string, number>): void;
13
+ import { BuildOutputAsset, ExecutionResult } from './bundler-execution-result';
14
+ export declare function logBuildStats(metafile: Metafile, initial: Map<string, InitialFileRecord>, budgetFailures: BudgetCalculatorResult[] | undefined, colors: boolean, changedFiles?: Set<string>, estimatedTransferSizes?: Map<string, number>, ssrOutputEnabled?: boolean, verbose?: boolean): string;
15
15
  export declare function calculateEstimatedTransferSizes(outputFiles: OutputFile[]): Promise<Map<string, number>>;
16
16
  export declare function withSpinner<T>(text: string, action: () => T | Promise<T>): Promise<T>;
17
17
  export declare function withNoProgress<T>(text: string, action: () => T | Promise<T>): Promise<T>;
18
- export declare function logMessages(logger: logging.LoggerApi, { errors, warnings }: {
19
- errors?: PartialMessage[];
20
- warnings?: PartialMessage[];
21
- }): Promise<void>;
22
18
  /**
23
19
  * Generates a syntax feature object map for Angular applications based on a list of targets.
24
20
  * A full set of feature names can be found here: https://esbuild.github.io/api/#supported
@@ -41,3 +37,4 @@ export declare function transformSupportedBrowsersToTargets(supportedBrowsers: s
41
37
  * @see https://esbuild.github.io/api/#target
42
38
  */
43
39
  export declare function getSupportedNodeTargets(): string[];
40
+ export declare function logMessages(logger: logging.LoggerApi, executionResult: ExecutionResult, options: NormalizedApplicationBuildOptions): Promise<void>;