@angular/build 19.0.0-next.8 → 19.0.0-rc.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.
Files changed (97) hide show
  1. package/LICENSE +5 -5
  2. package/package.json +22 -19
  3. package/src/builders/application/build-action.js +9 -9
  4. package/src/builders/application/chunk-optimizer.js +1 -4
  5. package/src/builders/application/execute-build.js +34 -6
  6. package/src/builders/application/execute-post-bundle.js +9 -1
  7. package/src/builders/application/index.d.ts +0 -16
  8. package/src/builders/application/index.js +15 -10
  9. package/src/builders/application/options.d.ts +11 -1
  10. package/src/builders/application/options.js +17 -10
  11. package/src/builders/application/results.d.ts +5 -3
  12. package/src/builders/application/schema.d.ts +86 -0
  13. package/src/builders/application/schema.js +19 -1
  14. package/src/builders/application/schema.json +73 -4
  15. package/src/builders/application/setup-bundling.d.ts +3 -1
  16. package/src/builders/application/setup-bundling.js +33 -6
  17. package/src/builders/dev-server/vite-server.d.ts +2 -2
  18. package/src/builders/dev-server/vite-server.js +46 -16
  19. package/src/index.d.ts +1 -0
  20. package/src/tools/angular/angular-host.d.ts +1 -1
  21. package/src/tools/angular/angular-host.js +1 -4
  22. package/src/tools/angular/compilation/angular-compilation.d.ts +1 -0
  23. package/src/tools/angular/compilation/aot-compilation.d.ts +1 -0
  24. package/src/tools/angular/compilation/aot-compilation.js +39 -0
  25. package/src/tools/angular/compilation/parallel-compilation.js +2 -2
  26. package/src/tools/angular/compilation/parallel-worker.d.ts +1 -0
  27. package/src/tools/angular/compilation/parallel-worker.js +5 -2
  28. package/src/tools/babel/plugins/add-code-coverage.d.ts +14 -0
  29. package/src/tools/babel/plugins/add-code-coverage.js +44 -0
  30. package/src/tools/babel/plugins/types.d.ts +20 -0
  31. package/src/tools/esbuild/angular/compiler-plugin.d.ts +3 -4
  32. package/src/tools/esbuild/angular/compiler-plugin.js +55 -34
  33. package/src/tools/esbuild/angular/component-stylesheets.d.ts +17 -18
  34. package/src/tools/esbuild/angular/component-stylesheets.js +63 -38
  35. package/src/tools/esbuild/angular/jit-plugin-callbacks.d.ts +1 -1
  36. package/src/tools/esbuild/angular/jit-plugin-callbacks.js +11 -3
  37. package/src/tools/esbuild/application-code-bundle.d.ts +5 -4
  38. package/src/tools/esbuild/application-code-bundle.js +66 -41
  39. package/src/tools/esbuild/bundler-context.d.ts +2 -1
  40. package/src/tools/esbuild/bundler-context.js +10 -12
  41. package/src/tools/esbuild/bundler-execution-result.d.ts +5 -2
  42. package/src/tools/esbuild/bundler-execution-result.js +5 -1
  43. package/src/tools/esbuild/commonjs-checker.js +2 -2
  44. package/src/tools/esbuild/compiler-plugin-options.d.ts +1 -4
  45. package/src/tools/esbuild/compiler-plugin-options.js +14 -36
  46. package/src/tools/esbuild/global-scripts.js +1 -1
  47. package/src/tools/esbuild/global-styles.js +4 -1
  48. package/src/tools/esbuild/index-html-generator.js +8 -0
  49. package/src/tools/esbuild/javascript-transformer-worker.d.ts +1 -0
  50. package/src/tools/esbuild/javascript-transformer-worker.js +5 -1
  51. package/src/tools/esbuild/javascript-transformer.d.ts +2 -2
  52. package/src/tools/esbuild/javascript-transformer.js +7 -3
  53. package/src/tools/esbuild/server-bundle-metadata-plugin.d.ts +22 -0
  54. package/src/tools/esbuild/server-bundle-metadata-plugin.js +36 -0
  55. package/src/tools/esbuild/stylesheets/bundle-options.d.ts +2 -0
  56. package/src/tools/esbuild/stylesheets/bundle-options.js +2 -1
  57. package/src/tools/esbuild/stylesheets/sass-language.js +4 -0
  58. package/src/tools/esbuild/stylesheets/stylesheet-plugin-factory.d.ts +9 -0
  59. package/src/tools/esbuild/utils.js +13 -31
  60. package/src/tools/sass/worker.js +19 -0
  61. package/src/tools/vite/middlewares/assets-middleware.d.ts +1 -1
  62. package/src/tools/vite/middlewares/assets-middleware.js +19 -3
  63. package/src/tools/vite/middlewares/component-middleware.d.ts +9 -0
  64. package/src/tools/vite/middlewares/component-middleware.js +33 -0
  65. package/src/tools/vite/middlewares/index.d.ts +1 -0
  66. package/src/tools/vite/middlewares/index.js +3 -1
  67. package/src/tools/vite/middlewares/ssr-middleware.js +13 -12
  68. package/src/tools/vite/plugins/setup-middlewares-plugin.d.ts +2 -1
  69. package/src/tools/vite/plugins/setup-middlewares-plugin.js +2 -1
  70. package/src/tools/vite/utils.d.ts +1 -0
  71. package/src/typings.d.ts +1 -1
  72. package/src/utils/environment-options.js +1 -1
  73. package/src/utils/index-file/auto-csp.d.ts +23 -0
  74. package/src/utils/index-file/auto-csp.js +283 -0
  75. package/src/utils/index-file/html-rewriting-stream.d.ts +5 -1
  76. package/src/utils/index-file/index-html-generator.d.ts +4 -0
  77. package/src/utils/index-file/index-html-generator.js +16 -0
  78. package/src/utils/index-file/inline-critical-css.js +17 -18
  79. package/src/utils/index-file/ngcm-attribute.d.ts +15 -0
  80. package/src/utils/index-file/ngcm-attribute.js +37 -0
  81. package/src/utils/index-file/valid-self-closing-tags.js +27 -0
  82. package/src/utils/normalize-cache.js +1 -1
  83. package/src/utils/server-rendering/fetch-patch.d.ts +1 -1
  84. package/src/utils/server-rendering/fetch-patch.js +2 -2
  85. package/src/utils/server-rendering/launch-server.d.ts +14 -0
  86. package/src/utils/server-rendering/launch-server.js +63 -0
  87. package/src/utils/server-rendering/load-esm-from-memory.d.ts +7 -0
  88. package/src/utils/server-rendering/manifest.d.ts +1 -1
  89. package/src/utils/server-rendering/manifest.js +4 -13
  90. package/src/utils/server-rendering/prerender.js +10 -6
  91. package/src/utils/server-rendering/render-worker.d.ts +4 -1
  92. package/src/utils/server-rendering/render-worker.js +13 -3
  93. package/src/utils/server-rendering/routes-extractor-worker.d.ts +5 -4
  94. package/src/utils/server-rendering/routes-extractor-worker.js +14 -4
  95. package/src/utils/server-rendering/utils.d.ts +11 -0
  96. package/src/utils/server-rendering/utils.js +17 -0
  97. package/src/utils/supported-browsers.js +1 -0
@@ -0,0 +1,20 @@
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.dev/license
7
+ */
8
+
9
+ declare module 'istanbul-lib-instrument' {
10
+ export interface Visitor {
11
+ enter(path: import('@babel/core').NodePath<types.Program>): void;
12
+ exit(path: import('@babel/core').NodePath<types.Program>): void;
13
+ }
14
+
15
+ export function programVisitor(
16
+ types: typeof import('@babel/core').types,
17
+ filePath?: string,
18
+ options?: { inputSourceMap?: object | null },
19
+ ): Visitor;
20
+ }
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import type { Plugin } from 'esbuild';
9
9
  import { LoadResultCache } from '../load-result-cache';
10
- import { BundleStylesheetOptions } from '../stylesheets/bundle-options';
10
+ import { ComponentStylesheetBundler } from './component-stylesheets';
11
11
  import { SourceFileCache } from './source-file-cache';
12
12
  export interface CompilerPluginOptions {
13
13
  sourcemap: boolean | 'external';
@@ -22,7 +22,6 @@ export interface CompilerPluginOptions {
22
22
  loadResultCache?: LoadResultCache;
23
23
  incremental: boolean;
24
24
  externalRuntimeStyles?: boolean;
25
+ instrumentForCoverage?: (request: string) => boolean;
25
26
  }
26
- export declare function createCompilerPlugin(pluginOptions: CompilerPluginOptions, styleOptions: BundleStylesheetOptions & {
27
- inlineStyleLanguage: string;
28
- }): Plugin;
27
+ export declare function createCompilerPlugin(pluginOptions: CompilerPluginOptions, stylesheetBundler: ComponentStylesheetBundler): Plugin;
@@ -43,11 +43,10 @@ const javascript_transformer_1 = require("../javascript-transformer");
43
43
  const load_result_cache_1 = require("../load-result-cache");
44
44
  const profiling_1 = require("../profiling");
45
45
  const compilation_state_1 = require("./compilation-state");
46
- const component_stylesheets_1 = require("./component-stylesheets");
47
46
  const file_reference_tracker_1 = require("./file-reference-tracker");
48
47
  const jit_plugin_callbacks_1 = require("./jit-plugin-callbacks");
49
48
  // eslint-disable-next-line max-lines-per-function
50
- function createCompilerPlugin(pluginOptions, styleOptions) {
49
+ function createCompilerPlugin(pluginOptions, stylesheetBundler) {
51
50
  return {
52
51
  name: 'angular-compiler',
53
52
  // eslint-disable-next-line max-lines-per-function
@@ -101,8 +100,6 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
101
100
  let shouldTsIgnoreJs = true;
102
101
  // Determines if transpilation should be handle by TypeScript or esbuild
103
102
  let useTypeScriptTranspilation = true;
104
- // Track incremental component stylesheet builds
105
- const stylesheetBundler = new component_stylesheets_1.ComponentStylesheetBundler(styleOptions, pluginOptions.incremental);
106
103
  let sharedTSCompilationState;
107
104
  // To fully invalidate files, track resource referenced files and their referencing source
108
105
  const referencedFileTracker = new file_reference_tracker_1.FileReferenceTracker();
@@ -121,14 +118,17 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
121
118
  // Angular compiler which does not have direct knowledge of transitive resource
122
119
  // dependencies or web worker processing.
123
120
  let modifiedFiles;
124
- let invalidatedStylesheetEntries;
125
121
  if (pluginOptions.sourceFileCache?.modifiedFiles.size &&
126
122
  referencedFileTracker &&
127
123
  !pluginOptions.noopTypeScriptCompilation) {
128
124
  // TODO: Differentiate between changed input files and stale output files
129
125
  modifiedFiles = referencedFileTracker.update(pluginOptions.sourceFileCache.modifiedFiles);
130
126
  pluginOptions.sourceFileCache.invalidate(modifiedFiles);
131
- invalidatedStylesheetEntries = stylesheetBundler.invalidate(modifiedFiles);
127
+ // External runtime styles are invalidated and rebuilt at the beginning of a rebuild to avoid
128
+ // the need to execute the application bundler for component style only changes.
129
+ if (!pluginOptions.externalRuntimeStyles) {
130
+ stylesheetBundler.invalidate(modifiedFiles);
131
+ }
132
132
  }
133
133
  if (!pluginOptions.noopTypeScriptCompilation &&
134
134
  compilation.update &&
@@ -140,7 +140,7 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
140
140
  fileReplacements: pluginOptions.fileReplacements,
141
141
  modifiedFiles,
142
142
  sourceFileCache: pluginOptions.sourceFileCache,
143
- async transformStylesheet(data, containingFile, stylesheetFile, order) {
143
+ async transformStylesheet(data, containingFile, stylesheetFile, order, className) {
144
144
  let stylesheetResult;
145
145
  // Stylesheet file only exists for external stylesheets
146
146
  if (stylesheetFile) {
@@ -148,8 +148,8 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
148
148
  }
149
149
  else {
150
150
  stylesheetResult = await stylesheetBundler.bundleInline(data, containingFile,
151
- // Inline stylesheets from a template style element are always CSS
152
- containingFile.endsWith('.html') ? 'css' : styleOptions.inlineStyleLanguage,
151
+ // Inline stylesheets from a template style element are always CSS; Otherwise, use default.
152
+ containingFile.endsWith('.html') ? 'css' : undefined,
153
153
  // When external runtime styles are enabled, an identifier for the style that does not change
154
154
  // based on the content is required to avoid emitted JS code changes. Any JS code changes will
155
155
  // invalid the output and force a full page reload for HMR cases. The containing file and order
@@ -158,14 +158,16 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
158
158
  ? (0, node_crypto_1.createHash)('sha-256')
159
159
  .update(containingFile)
160
160
  .update((order ?? 0).toString())
161
+ .update(className ?? '')
161
162
  .digest('hex')
162
163
  : undefined);
163
164
  }
164
- const { contents, outputFiles, metafile, referencedFiles, errors, warnings } = stylesheetResult;
165
- if (errors) {
166
- (result.errors ??= []).push(...errors);
165
+ (result.warnings ??= []).push(...stylesheetResult.warnings);
166
+ if (stylesheetResult.errors) {
167
+ (result.errors ??= []).push(...stylesheetResult.errors);
168
+ return '';
167
169
  }
168
- (result.warnings ??= []).push(...warnings);
170
+ const { contents, outputFiles, metafile, referencedFiles } = stylesheetResult;
169
171
  additionalResults.set(stylesheetFile ?? containingFile, {
170
172
  outputFiles,
171
173
  metafile,
@@ -215,7 +217,7 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
215
217
  let referencedFiles;
216
218
  let externalStylesheets;
217
219
  try {
218
- const initializationResult = await compilation.initialize(pluginOptions.tsconfig, hostOptions, createCompilerOptionsTransformer(setupWarnings, pluginOptions, preserveSymlinks));
220
+ const initializationResult = await compilation.initialize(pluginOptions.tsconfig, hostOptions, createCompilerOptionsTransformer(setupWarnings, pluginOptions, preserveSymlinks, build.initialOptions.conditions));
219
221
  shouldTsIgnoreJs = !initializationResult.compilerOptions.allowJs;
220
222
  // Isolated modules option ensures safe non-TypeScript transpilation.
221
223
  // Typescript printing support for sourcemaps is not yet integrated.
@@ -250,13 +252,6 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
250
252
  for (const [stylesheetFile, externalId] of externalStylesheets) {
251
253
  await bundleExternalStylesheet(stylesheetBundler, stylesheetFile, externalId, result, additionalResults);
252
254
  }
253
- // Process any updated stylesheets
254
- if (invalidatedStylesheetEntries) {
255
- for (const stylesheetFile of invalidatedStylesheetEntries) {
256
- // externalId is already linked in the bundler context so only enabling is required here
257
- await bundleExternalStylesheet(stylesheetBundler, stylesheetFile, true, result, additionalResults);
258
- }
259
- }
260
255
  }
261
256
  // Update TypeScript file output cache for all affected files
262
257
  try {
@@ -339,13 +334,27 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
339
334
  // A string indicates untransformed output from the TS/NG compiler.
340
335
  // This step is unneeded when using esbuild transpilation.
341
336
  const sideEffects = await hasSideEffects(request);
342
- contents = await javascriptTransformer.transformData(request, contents, true /* skipLinker */, sideEffects);
337
+ const instrumentForCoverage = pluginOptions.instrumentForCoverage?.(request);
338
+ contents = await javascriptTransformer.transformData(request, contents, true /* skipLinker */, sideEffects, instrumentForCoverage);
343
339
  // Store as the returned Uint8Array to allow caching the fully transformed code
344
340
  typeScriptFileCache.set(request, contents);
345
341
  }
342
+ let loader;
343
+ if (useTypeScriptTranspilation || isJS) {
344
+ // TypeScript has transpiled to JS or is already JS
345
+ loader = 'js';
346
+ }
347
+ else if (request.at(-1) === 'x') {
348
+ // TSX and TS have different syntax rules. Only set if input is a TSX file.
349
+ loader = 'tsx';
350
+ }
351
+ else {
352
+ // Otherwise, directly bundle TS
353
+ loader = 'ts';
354
+ }
346
355
  return {
347
356
  contents,
348
- loader: useTypeScriptTranspilation || isJS ? 'js' : 'ts',
357
+ loader,
349
358
  };
350
359
  });
351
360
  build.onLoad({ filter: /\.[cm]?js$/ }, (0, load_result_cache_1.createCachedLoad)(pluginOptions.loadResultCache, async (args) => {
@@ -360,7 +369,7 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
360
369
  }));
361
370
  // Setup bundling of component templates and stylesheets when in JIT mode
362
371
  if (pluginOptions.jit) {
363
- (0, jit_plugin_callbacks_1.setupJitPluginCallbacks)(build, stylesheetBundler, additionalResults, styleOptions.inlineStyleLanguage, pluginOptions.loadResultCache);
372
+ (0, jit_plugin_callbacks_1.setupJitPluginCallbacks)(build, stylesheetBundler, additionalResults, pluginOptions.loadResultCache);
364
373
  }
365
374
  build.onEnd((result) => {
366
375
  // Ensure other compilations are unblocked if the main compilation throws during start
@@ -383,7 +392,6 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
383
392
  });
384
393
  build.onDispose(() => {
385
394
  sharedTSCompilationState?.dispose();
386
- void stylesheetBundler.dispose();
387
395
  void compilation.close?.();
388
396
  void cacheStore?.close();
389
397
  });
@@ -404,17 +412,25 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
404
412
  };
405
413
  }
406
414
  async function bundleExternalStylesheet(stylesheetBundler, stylesheetFile, externalId, result, additionalResults) {
407
- const { outputFiles, metafile, errors, warnings } = await stylesheetBundler.bundleFile(stylesheetFile, externalId);
408
- if (errors) {
409
- (result.errors ??= []).push(...errors);
415
+ const styleResult = await stylesheetBundler.bundleFile(stylesheetFile, externalId);
416
+ (result.warnings ??= []).push(...styleResult.warnings);
417
+ if (styleResult.errors) {
418
+ (result.errors ??= []).push(...styleResult.errors);
419
+ }
420
+ else {
421
+ const { outputFiles, metafile } = styleResult;
422
+ // Clear inputs to prevent triggering a rebuild of the application code for component
423
+ // stylesheet file only changes when the dev server enables the internal-only external
424
+ // stylesheet option. This does not affect builds since only the dev server can enable
425
+ // the internal option.
426
+ metafile.inputs = {};
427
+ additionalResults.set(stylesheetFile, {
428
+ outputFiles,
429
+ metafile,
430
+ });
410
431
  }
411
- (result.warnings ??= []).push(...warnings);
412
- additionalResults.set(stylesheetFile, {
413
- outputFiles,
414
- metafile,
415
- });
416
432
  }
417
- function createCompilerOptionsTransformer(setupWarnings, pluginOptions, preserveSymlinks) {
433
+ function createCompilerOptionsTransformer(setupWarnings, pluginOptions, preserveSymlinks, customConditions) {
418
434
  return (compilerOptions) => {
419
435
  // target of 9 is ES2022 (using the number avoids an expensive import of typescript just for an enum)
420
436
  if (compilerOptions.target === undefined || compilerOptions.target < 9 /** ES2022 */) {
@@ -462,6 +478,11 @@ function createCompilerOptionsTransformer(setupWarnings, pluginOptions, preserve
462
478
  notes: [{ text: `The 'module' option will be set to 'ES2022' instead.` }],
463
479
  });
464
480
  }
481
+ // Synchronize custom resolve conditions.
482
+ // Set if using the supported bundler resolution mode (bundler is the default in new projects)
483
+ if (compilerOptions.moduleResolution === 100 /* ModuleResolutionKind.Bundler */) {
484
+ compilerOptions.customConditions = customConditions;
485
+ }
465
486
  return {
466
487
  ...compilerOptions,
467
488
  noEmitOnError: false,
@@ -5,8 +5,12 @@
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.dev/license
7
7
  */
8
- import { OutputFile } from 'esbuild';
8
+ import { BundleContextResult } from '../bundler-context';
9
9
  import { BundleStylesheetOptions } from '../stylesheets/bundle-options';
10
+ export type ComponentStylesheetResult = BundleContextResult & {
11
+ contents: string;
12
+ referencedFiles: Set<string> | undefined;
13
+ };
10
14
  /**
11
15
  * Bundles component stylesheets. A stylesheet can be either an inline stylesheet that
12
16
  * is contained within the Component's metadata definition or an external file referenced
@@ -15,35 +19,30 @@ import { BundleStylesheetOptions } from '../stylesheets/bundle-options';
15
19
  export declare class ComponentStylesheetBundler {
16
20
  #private;
17
21
  private readonly options;
22
+ private readonly defaultInlineLanguage;
18
23
  private readonly incremental;
19
24
  /**
20
25
  *
21
26
  * @param options An object containing the stylesheet bundling options.
22
27
  * @param cache A load result cache to use when bundling.
23
28
  */
24
- constructor(options: BundleStylesheetOptions, incremental: boolean);
25
- bundleFile(entry: string, externalId?: string | boolean): Promise<{
26
- errors: import("esbuild").Message[] | undefined;
27
- warnings: import("esbuild").Message[];
28
- contents: string;
29
- outputFiles: OutputFile[];
30
- metafile: import("esbuild").Metafile | undefined;
31
- referencedFiles: Set<string> | undefined;
32
- }>;
33
- bundleInline(data: string, filename: string, language: string, externalId?: string): Promise<{
34
- errors: import("esbuild").Message[] | undefined;
35
- warnings: import("esbuild").Message[];
36
- contents: string;
37
- outputFiles: OutputFile[];
38
- metafile: import("esbuild").Metafile | undefined;
39
- referencedFiles: Set<string> | undefined;
40
- }>;
29
+ constructor(options: BundleStylesheetOptions, defaultInlineLanguage: string, incremental: boolean);
30
+ /**
31
+ * Bundle a file-based component stylesheet for use within an AOT compiled Angular application.
32
+ * @param entry The file path of the stylesheet.
33
+ * @param externalId Either an external identifier string for initial bundling or a boolean for rebuilds, if external.
34
+ * @param direct If true, the output will be used directly by the builder; false if used inside the compiler plugin.
35
+ * @returns A component bundle result object.
36
+ */
37
+ bundleFile(entry: string, externalId?: string | boolean, direct?: boolean): Promise<ComponentStylesheetResult>;
38
+ bundleInline(data: string, filename: string, language?: string, externalId?: string): Promise<ComponentStylesheetResult>;
41
39
  /**
42
40
  * Invalidates both file and inline based component style bundling state for a set of modified files.
43
41
  * @param files The group of files that have been modified
44
42
  * @returns An array of file based stylesheet entries if any were invalidated; otherwise, undefined.
45
43
  */
46
44
  invalidate(files: Iterable<string>): string[] | undefined;
45
+ collectReferencedFiles(): string[];
47
46
  dispose(): Promise<void>;
48
47
  private extractResult;
49
48
  }
@@ -24,6 +24,7 @@ const bundle_options_1 = require("../stylesheets/bundle-options");
24
24
  */
25
25
  class ComponentStylesheetBundler {
26
26
  options;
27
+ defaultInlineLanguage;
27
28
  incremental;
28
29
  #fileContexts = new cache_1.MemoryCache();
29
30
  #inlineContexts = new cache_1.MemoryCache();
@@ -32,17 +33,26 @@ class ComponentStylesheetBundler {
32
33
  * @param options An object containing the stylesheet bundling options.
33
34
  * @param cache A load result cache to use when bundling.
34
35
  */
35
- constructor(options, incremental) {
36
+ constructor(options, defaultInlineLanguage, incremental) {
36
37
  this.options = options;
38
+ this.defaultInlineLanguage = defaultInlineLanguage;
37
39
  this.incremental = incremental;
38
40
  }
39
- async bundleFile(entry, externalId) {
41
+ /**
42
+ * Bundle a file-based component stylesheet for use within an AOT compiled Angular application.
43
+ * @param entry The file path of the stylesheet.
44
+ * @param externalId Either an external identifier string for initial bundling or a boolean for rebuilds, if external.
45
+ * @param direct If true, the output will be used directly by the builder; false if used inside the compiler plugin.
46
+ * @returns A component bundle result object.
47
+ */
48
+ async bundleFile(entry, externalId, direct) {
40
49
  const bundlerContext = await this.#fileContexts.getOrCreate(entry, () => {
41
50
  return new bundler_context_1.BundlerContext(this.options.workspaceRoot, this.incremental, (loadCache) => {
42
51
  const buildOptions = (0, bundle_options_1.createStylesheetBundleOptions)(this.options, loadCache);
43
52
  if (externalId) {
44
53
  (0, node_assert_1.default)(typeof externalId === 'string', 'Initial external component stylesheets must have a string identifier');
45
54
  buildOptions.entryPoints = { [externalId]: entry };
55
+ buildOptions.entryNames = '[name]';
46
56
  delete buildOptions.publicPath;
47
57
  }
48
58
  else {
@@ -51,9 +61,9 @@ class ComponentStylesheetBundler {
51
61
  return buildOptions;
52
62
  });
53
63
  });
54
- return this.extractResult(await bundlerContext.bundle(), bundlerContext.watchFiles, !!externalId);
64
+ return this.extractResult(await bundlerContext.bundle(), bundlerContext.watchFiles, !!externalId, !!direct);
55
65
  }
56
- async bundleInline(data, filename, language, externalId) {
66
+ async bundleInline(data, filename, language = this.defaultInlineLanguage, externalId) {
57
67
  // Use a hash of the inline stylesheet content to ensure a consistent identifier. External stylesheets will resolve
58
68
  // to the actual stylesheet file path.
59
69
  // TODO: Consider xxhash instead for hashing
@@ -70,6 +80,7 @@ class ComponentStylesheetBundler {
70
80
  });
71
81
  if (externalId) {
72
82
  buildOptions.entryPoints = { [externalId]: `${namespace};${entry}` };
83
+ buildOptions.entryNames = '[name]';
73
84
  delete buildOptions.publicPath;
74
85
  }
75
86
  else {
@@ -100,7 +111,7 @@ class ComponentStylesheetBundler {
100
111
  });
101
112
  });
102
113
  // Extract the result of the bundling from the output files
103
- return this.extractResult(await bundlerContext.bundle(), bundlerContext.watchFiles, !!externalId);
114
+ return this.extractResult(await bundlerContext.bundle(), bundlerContext.watchFiles, !!externalId, false);
104
115
  }
105
116
  /**
106
117
  * Invalidates both file and inline based component style bundling state for a set of modified files.
@@ -124,61 +135,75 @@ class ComponentStylesheetBundler {
124
135
  }
125
136
  return entries;
126
137
  }
138
+ collectReferencedFiles() {
139
+ const files = [];
140
+ for (const context of this.#fileContexts.values()) {
141
+ files.push(...context.watchFiles);
142
+ }
143
+ return files;
144
+ }
127
145
  async dispose() {
128
146
  const contexts = [...this.#fileContexts.values(), ...this.#inlineContexts.values()];
129
147
  this.#fileContexts.clear();
130
148
  this.#inlineContexts.clear();
131
149
  await Promise.allSettled(contexts.map((context) => context.dispose()));
132
150
  }
133
- extractResult(result, referencedFiles, external) {
151
+ extractResult(result, referencedFiles, external, direct) {
134
152
  let contents = '';
135
- let metafile;
136
153
  const outputFiles = [];
137
- if (!result.errors) {
138
- for (const outputFile of result.outputFiles) {
139
- const filename = node_path_1.default.basename(outputFile.path);
140
- if (outputFile.type === bundler_context_1.BuildOutputFileType.Media || filename.endsWith('.css.map')) {
141
- // The output files could also contain resources (images/fonts/etc.) that were referenced and the map files.
142
- // Clone the output file to avoid amending the original path which would causes problems during rebuild.
143
- const clonedOutputFile = outputFile.clone();
144
- // Needed for Bazel as otherwise the files will not be written in the correct place,
145
- // this is because esbuild will resolve the output file from the outdir which is currently set to `workspaceRoot` twice,
146
- // once in the stylesheet and the other in the application code bundler.
147
- // Ex: `../../../../../app.component.css.map`.
154
+ const { errors, warnings } = result;
155
+ if (errors) {
156
+ return { errors, warnings, referencedFiles, contents: '' };
157
+ }
158
+ for (const outputFile of result.outputFiles) {
159
+ const filename = node_path_1.default.basename(outputFile.path);
160
+ if (outputFile.type === bundler_context_1.BuildOutputFileType.Media || filename.endsWith('.css.map')) {
161
+ // The output files could also contain resources (images/fonts/etc.) that were referenced and the map files.
162
+ // Clone the output file to avoid amending the original path which would causes problems during rebuild.
163
+ const clonedOutputFile = outputFile.clone();
164
+ // Needed for Bazel as otherwise the files will not be written in the correct place,
165
+ // this is because esbuild will resolve the output file from the outdir which is currently set to `workspaceRoot` twice,
166
+ // once in the stylesheet and the other in the application code bundler.
167
+ // Ex: `../../../../../app.component.css.map`.
168
+ if (!direct) {
148
169
  clonedOutputFile.path = node_path_1.default.join(this.options.workspaceRoot, outputFile.path);
149
- outputFiles.push(clonedOutputFile);
150
170
  }
151
- else if (filename.endsWith('.css')) {
152
- if (external) {
153
- const clonedOutputFile = outputFile.clone();
171
+ outputFiles.push(clonedOutputFile);
172
+ }
173
+ else if (filename.endsWith('.css')) {
174
+ if (external) {
175
+ const clonedOutputFile = outputFile.clone();
176
+ if (!direct) {
154
177
  clonedOutputFile.path = node_path_1.default.join(this.options.workspaceRoot, outputFile.path);
155
- outputFiles.push(clonedOutputFile);
156
- contents = node_path_1.default.posix.join(this.options.publicPath ?? '', filename);
157
- }
158
- else {
159
- contents = outputFile.text;
160
178
  }
179
+ outputFiles.push(clonedOutputFile);
180
+ contents = node_path_1.default.posix.join(this.options.publicPath ?? '', filename);
161
181
  }
162
182
  else {
163
- throw new Error(`Unexpected non CSS/Media file "${filename}" outputted during component stylesheet processing.`);
183
+ contents = outputFile.text;
164
184
  }
165
185
  }
166
- metafile = result.metafile;
167
- // Remove entryPoint fields from outputs to prevent the internal component styles from being
168
- // treated as initial files. Also mark the entry as a component resource for stat reporting.
169
- Object.values(metafile.outputs).forEach((output) => {
170
- delete output.entryPoint;
171
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
172
- output['ng-component'] = true;
173
- });
186
+ else {
187
+ throw new Error(`Unexpected non CSS/Media file "${filename}" outputted during component stylesheet processing.`);
188
+ }
174
189
  }
190
+ const metafile = result.metafile;
191
+ // Remove entryPoint fields from outputs to prevent the internal component styles from being
192
+ // treated as initial files. Also mark the entry as a component resource for stat reporting.
193
+ Object.values(metafile.outputs).forEach((output) => {
194
+ delete output.entryPoint;
195
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
196
+ output['ng-component'] = true;
197
+ });
175
198
  return {
176
- errors: result.errors,
177
- warnings: result.warnings,
199
+ errors,
200
+ warnings,
178
201
  contents,
179
202
  outputFiles,
180
203
  metafile,
181
204
  referencedFiles,
205
+ externalImports: result.externalImports,
206
+ initialFiles: new Map(),
182
207
  };
183
208
  }
184
209
  }
@@ -20,4 +20,4 @@ import { ComponentStylesheetBundler } from './component-stylesheets';
20
20
  export declare function setupJitPluginCallbacks(build: PluginBuild, stylesheetBundler: ComponentStylesheetBundler, additionalResultFiles: Map<string, {
21
21
  outputFiles?: OutputFile[];
22
22
  metafile?: Metafile;
23
- }>, inlineStyleLanguage: string, loadCache?: LoadResultCache): void;
23
+ }>, loadCache?: LoadResultCache): void;
@@ -51,7 +51,7 @@ async function loadEntry(entry, root, skipRead) {
51
51
  * @param styleOptions The options to use when bundling stylesheets.
52
52
  * @param additionalResultFiles A Map where stylesheet resources will be added.
53
53
  */
54
- function setupJitPluginCallbacks(build, stylesheetBundler, additionalResultFiles, inlineStyleLanguage, loadCache) {
54
+ function setupJitPluginCallbacks(build, stylesheetBundler, additionalResultFiles, loadCache) {
55
55
  const root = build.initialOptions.absWorkingDir ?? '';
56
56
  // Add a resolve callback to capture and parse any JIT URIs that were added by the
57
57
  // JIT resource TypeScript transformer.
@@ -90,9 +90,17 @@ function setupJitPluginCallbacks(build, stylesheetBundler, additionalResultFiles
90
90
  stylesheetResult = await stylesheetBundler.bundleFile(entry.path);
91
91
  }
92
92
  else {
93
- stylesheetResult = await stylesheetBundler.bundleInline(entry.contents, entry.path, inlineStyleLanguage);
93
+ stylesheetResult = await stylesheetBundler.bundleInline(entry.contents, entry.path);
94
94
  }
95
- const { contents, outputFiles, errors, warnings, metafile, referencedFiles } = stylesheetResult;
95
+ const { errors, warnings, referencedFiles } = stylesheetResult;
96
+ if (stylesheetResult.errors) {
97
+ return {
98
+ errors,
99
+ warnings,
100
+ watchFiles: referencedFiles && [...referencedFiles],
101
+ };
102
+ }
103
+ const { contents, outputFiles, metafile } = stylesheetResult;
96
104
  additionalResultFiles.set(entry.path, { outputFiles, metafile });
97
105
  return {
98
106
  errors,
@@ -7,10 +7,11 @@
7
7
  */
8
8
  import type { BuildOptions } from 'esbuild';
9
9
  import type { NormalizedApplicationBuildOptions } from '../../builders/application/options';
10
+ import { ComponentStylesheetBundler } from './angular/component-stylesheets';
10
11
  import { SourceFileCache } from './angular/source-file-cache';
11
12
  import { BundlerOptionsFactory } from './bundler-context';
12
- export declare function createBrowserCodeBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], sourceFileCache?: SourceFileCache): BuildOptions;
13
- export declare function createBrowserPolyfillBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], sourceFileCache?: SourceFileCache): BuildOptions | BundlerOptionsFactory | undefined;
13
+ export declare function createBrowserCodeBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], sourceFileCache: SourceFileCache, stylesheetBundler: ComponentStylesheetBundler): BuildOptions;
14
+ export declare function createBrowserPolyfillBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], sourceFileCache: SourceFileCache, stylesheetBundler: ComponentStylesheetBundler): BuildOptions | BundlerOptionsFactory | undefined;
14
15
  export declare function createServerPolyfillBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], sourceFileCache?: SourceFileCache): BundlerOptionsFactory | undefined;
15
- export declare function createServerMainCodeBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], sourceFileCache: SourceFileCache): BuildOptions;
16
- export declare function createSsrEntryCodeBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], sourceFileCache: SourceFileCache): BuildOptions;
16
+ export declare function createServerMainCodeBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], sourceFileCache: SourceFileCache, stylesheetBundler: ComponentStylesheetBundler): BuildOptions;
17
+ export declare function createSsrEntryCodeBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], sourceFileCache: SourceFileCache, stylesheetBundler: ComponentStylesheetBundler): BuildOptions;