@angular-devkit/build-angular 17.0.1 → 17.0.3

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,15 +1,15 @@
1
1
  {
2
2
  "name": "@angular-devkit/build-angular",
3
- "version": "17.0.1",
3
+ "version": "17.0.3",
4
4
  "description": "Angular Webpack Build Facade",
5
5
  "main": "src/index.js",
6
6
  "typings": "src/index.d.ts",
7
7
  "builders": "builders.json",
8
8
  "dependencies": {
9
9
  "@ampproject/remapping": "2.2.1",
10
- "@angular-devkit/architect": "0.1700.1",
11
- "@angular-devkit/build-webpack": "0.1700.1",
12
- "@angular-devkit/core": "17.0.1",
10
+ "@angular-devkit/architect": "0.1700.3",
11
+ "@angular-devkit/build-webpack": "0.1700.3",
12
+ "@angular-devkit/core": "17.0.3",
13
13
  "@babel/core": "7.23.2",
14
14
  "@babel/generator": "7.23.0",
15
15
  "@babel/helper-annotate-as-pure": "7.22.5",
@@ -20,7 +20,7 @@
20
20
  "@babel/preset-env": "7.23.2",
21
21
  "@babel/runtime": "7.23.2",
22
22
  "@discoveryjs/json-ext": "0.5.7",
23
- "@ngtools/webpack": "17.0.1",
23
+ "@ngtools/webpack": "17.0.3",
24
24
  "@vitejs/plugin-basic-ssl": "1.0.1",
25
25
  "ansi-colors": "4.1.3",
26
26
  "autoprefixer": "10.4.16",
@@ -71,7 +71,9 @@ async function executePostBundleSteps(options, outputFiles, assetFiles, initialF
71
71
  // If localization is enabled, service worker is handled in the inlining process.
72
72
  if (serviceWorker) {
73
73
  try {
74
- const serviceWorkerResult = await (0, service_worker_1.augmentAppWithServiceWorkerEsbuild)(workspaceRoot, serviceWorker, options.baseHref || '/', outputFiles, assetFiles);
74
+ const serviceWorkerResult = await (0, service_worker_1.augmentAppWithServiceWorkerEsbuild)(workspaceRoot, serviceWorker, options.baseHref || '/',
75
+ // Ensure additional files recently added are used
76
+ [...outputFiles, ...additionalOutputFiles], assetFiles);
75
77
  additionalOutputFiles.push((0, utils_1.createOutputFileFromText)('ngsw.json', serviceWorkerResult.manifest, bundler_context_1.BuildOutputFileType.Browser));
76
78
  additionalAssets.push(...serviceWorkerResult.assetFiles);
77
79
  }
@@ -9,6 +9,7 @@
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.loadActiveTranslations = exports.inlineI18n = void 0;
11
11
  const node_path_1 = require("node:path");
12
+ const bundler_context_1 = require("../../tools/esbuild/bundler-context");
12
13
  const i18n_inliner_1 = require("../../tools/esbuild/i18n-inliner");
13
14
  const environment_options_1 = require("../../utils/environment-options");
14
15
  const i18n_options_1 = require("../../utils/i18n-options");
@@ -72,8 +73,13 @@ async function inlineI18n(options, executionResult, initialFiles) {
72
73
  finally {
73
74
  await inliner.close();
74
75
  }
75
- // Update the result with all localized files
76
- executionResult.outputFiles = updatedOutputFiles;
76
+ // Update the result with all localized files.
77
+ executionResult.outputFiles = [
78
+ // Root files are not modified.
79
+ ...executionResult.outputFiles.filter(({ type }) => type === bundler_context_1.BuildOutputFileType.Root),
80
+ // Updated files for each locale.
81
+ ...updatedOutputFiles,
82
+ ];
77
83
  // Assets are only changed if not using the flat output option
78
84
  if (options.i18nOptions.flatOutput !== true) {
79
85
  executionResult.assetFiles = updatedAssetFiles;
@@ -18,8 +18,6 @@ const UNSUPPORTED_OPTIONS = [
18
18
  'webWorkerTsConfig',
19
19
  ];
20
20
  function logBuilderStatusWarnings(options, { logger }) {
21
- logger.warn(`The 'browser-esbuild' builder is a compatibility builder which will be removed in a future major ` +
22
- `version in favor of the 'application' builder.`);
23
21
  // Validate supported options
24
22
  for (const unsupportedOption of UNSUPPORTED_OPTIONS) {
25
23
  const value = options[unsupportedOption];
@@ -25,5 +25,5 @@ export declare function serveWithVite(serverOptions: NormalizedDevServerOptions,
25
25
  middleware?: Connect.NextHandleFunction[];
26
26
  buildPlugins?: Plugin[];
27
27
  }): AsyncIterableIterator<DevServerBuilderOutput>;
28
- export declare function setupServer(serverOptions: NormalizedDevServerOptions, outputFiles: Map<string, OutputFileRecord>, assets: Map<string, string>, preserveSymlinks: boolean | undefined, externalMetadata: ExternalResultMetadata, ssr: boolean, prebundleTransformer: JavaScriptTransformer, target: string[], extensionMiddleware?: Connect.NextHandleFunction[], indexHtmlTransformer?: (content: string) => Promise<string>): Promise<InlineConfig>;
28
+ export declare function setupServer(serverOptions: NormalizedDevServerOptions, outputFiles: Map<string, OutputFileRecord>, assets: Map<string, string>, preserveSymlinks: boolean | undefined, externalMetadata: ExternalResultMetadata, ssr: boolean, prebundleTransformer: JavaScriptTransformer, target: string[], extensionMiddleware?: Connect.NextHandleFunction[], indexHtmlTransformer?: (content: string) => Promise<string>, thirdPartySourcemaps?: boolean): Promise<InlineConfig>;
29
29
  export {};
@@ -44,6 +44,7 @@ const javascript_transformer_1 = require("../../tools/esbuild/javascript-transfo
44
44
  const rxjs_esm_resolution_plugin_1 = require("../../tools/esbuild/rxjs-esm-resolution-plugin");
45
45
  const utils_1 = require("../../tools/esbuild/utils");
46
46
  const i18n_locale_plugin_1 = require("../../tools/vite/i18n-locale-plugin");
47
+ const utils_2 = require("../../utils");
47
48
  const render_page_1 = require("../../utils/server-rendering/render-page");
48
49
  const supported_browsers_1 = require("../../utils/supported-browsers");
49
50
  const webpack_browser_config_1 = require("../../utils/webpack-browser-config");
@@ -86,12 +87,13 @@ async function* serveWithVite(serverOptions, builderName, context, transformers,
86
87
  // When localization is enabled with a single locale, force a flat path to maintain behavior with the existing Webpack-based dev server.
87
88
  browserOptions.forceI18nFlatOutput = true;
88
89
  }
90
+ const { vendor: thirdPartySourcemaps } = (0, utils_2.normalizeSourceMaps)(browserOptions.sourceMap ?? false);
89
91
  // Setup the prebundling transformer that will be shared across Vite prebundling requests
90
92
  const prebundleTransformer = new javascript_transformer_1.JavaScriptTransformer(
91
93
  // Always enable JIT linking to support applications built with and without AOT.
92
94
  // In a development environment the additional scope information does not
93
95
  // have a negative effect unlike production where final output size is relevant.
94
- { sourcemap: true, jit: true, thirdPartySourcemaps: true }, 1, true);
96
+ { sourcemap: true, jit: true, thirdPartySourcemaps }, 1, true);
95
97
  // Extract output index from options
96
98
  // TODO: Provide this info from the build results
97
99
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -115,9 +117,9 @@ async function* serveWithVite(serverOptions, builderName, context, transformers,
115
117
  await prebundleTransformer.close();
116
118
  deferred?.();
117
119
  });
118
- const build = builderName === '@angular-devkit/build-angular:application'
119
- ? application_1.buildApplicationInternal
120
- : browser_esbuild_1.buildEsbuildBrowser;
120
+ const build = builderName === '@angular-devkit/build-angular:browser-esbuild'
121
+ ? browser_esbuild_1.buildEsbuildBrowser
122
+ : application_1.buildApplicationInternal;
121
123
  // TODO: Switch this to an architect schedule call when infrastructure settings are supported
122
124
  for await (const result of build(
123
125
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -186,7 +188,7 @@ async function* serveWithVite(serverOptions, builderName, context, transformers,
186
188
  const browsers = (0, supported_browsers_1.getSupportedBrowsers)(projectRoot, context.logger);
187
189
  const target = (0, utils_1.transformSupportedBrowsersToTargets)(browsers);
188
190
  // Setup server and start listening
189
- const serverConfiguration = await setupServer(serverOptions, generatedFiles, assetFiles, browserOptions.preserveSymlinks, externalMetadata, !!browserOptions.ssr, prebundleTransformer, target, extensions?.middleware, transformers?.indexHtml);
191
+ const serverConfiguration = await setupServer(serverOptions, generatedFiles, assetFiles, browserOptions.preserveSymlinks, externalMetadata, !!browserOptions.ssr, prebundleTransformer, target, extensions?.middleware, transformers?.indexHtml, thirdPartySourcemaps);
190
192
  server = await createServer(serverConfiguration);
191
193
  await server.listen();
192
194
  if (serverConfiguration.ssr?.optimizeDeps?.disabled === false) {
@@ -305,7 +307,7 @@ function analyzeResultFiles(normalizePath, htmlIndexPath, resultFiles, generated
305
307
  }
306
308
  }
307
309
  // eslint-disable-next-line max-lines-per-function
308
- async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks, externalMetadata, ssr, prebundleTransformer, target, extensionMiddleware, indexHtmlTransformer) {
310
+ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks, externalMetadata, ssr, prebundleTransformer, target, extensionMiddleware, indexHtmlTransformer, thirdPartySourcemaps = false) {
309
311
  const proxy = await (0, load_proxy_config_1.loadProxyConfiguration)(serverOptions.workspaceRoot, serverOptions.proxyConfig, true);
310
312
  // dynamically import Vite for ESM compatibility
311
313
  const { normalizePath } = await Promise.resolve().then(() => __importStar(require('vite')));
@@ -372,6 +374,7 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
372
374
  ssr: true,
373
375
  prebundleTransformer,
374
376
  target,
377
+ thirdPartySourcemaps,
375
378
  }),
376
379
  },
377
380
  plugins: [
@@ -427,7 +430,7 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
427
430
  }
428
431
  const remappedMap = (0, remapping_1.default)([result.map, map], () => null);
429
432
  // Set the sourcemap root to the workspace root. This is needed since we set a virtual path as root.
430
- remappedMap.sourceRoot = serverOptions.workspaceRoot + '/';
433
+ remappedMap.sourceRoot = normalizePath(serverOptions.workspaceRoot) + '/';
431
434
  return {
432
435
  ...result,
433
436
  map: remappedMap,
@@ -569,6 +572,7 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
569
572
  ssr: false,
570
573
  prebundleTransformer,
571
574
  target,
575
+ thirdPartySourcemaps,
572
576
  }),
573
577
  };
574
578
  if (serverOptions.ssl) {
@@ -617,10 +621,10 @@ function pathnameWithoutServePath(url, serverOptions) {
617
621
  }
618
622
  return pathname;
619
623
  }
620
- function getDepOptimizationConfig({ disabled, exclude, include, target, prebundleTransformer, ssr, }) {
624
+ function getDepOptimizationConfig({ disabled, exclude, include, target, prebundleTransformer, ssr, thirdPartySourcemaps, }) {
621
625
  const plugins = [
622
626
  {
623
- name: `angular-vite-optimize-deps${ssr ? '-ssr' : ''}`,
627
+ name: `angular-vite-optimize-deps${ssr ? '-ssr' : ''}${thirdPartySourcemaps ? '-vendor-sourcemap' : ''}`,
624
628
  setup(build) {
625
629
  build.onLoad({ filter: /\.[cm]?js$/ }, async (args) => {
626
630
  return {
@@ -37,9 +37,9 @@ exports.createCompilerPlugin = void 0;
37
37
  const node_assert_1 = __importDefault(require("node:assert"));
38
38
  const promises_1 = require("node:fs/promises");
39
39
  const path = __importStar(require("node:path"));
40
- const node_url_1 = require("node:url");
41
40
  const environment_options_1 = require("../../../utils/environment-options");
42
41
  const javascript_transformer_1 = require("../javascript-transformer");
42
+ const load_result_cache_1 = require("../load-result-cache");
43
43
  const profiling_1 = require("../profiling");
44
44
  const compilation_1 = require("./compilation");
45
45
  const compilation_state_1 = require("./compilation-state");
@@ -216,7 +216,7 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
216
216
  try {
217
217
  await (0, profiling_1.profileAsync)('NG_EMIT_TS', async () => {
218
218
  for (const { filename, contents } of await compilation.emitAffectedFiles()) {
219
- typeScriptFileCache.set((0, node_url_1.pathToFileURL)(filename).href, contents);
219
+ typeScriptFileCache.set(path.normalize(filename), contents);
220
220
  }
221
221
  });
222
222
  }
@@ -253,7 +253,7 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
253
253
  return result;
254
254
  });
255
255
  build.onLoad({ filter: /\.[cm]?[jt]sx?$/ }, async (args) => {
256
- const request = pluginOptions.fileReplacements?.[args.path] ?? args.path;
256
+ const request = path.normalize(pluginOptions.fileReplacements?.[path.normalize(args.path)] ?? args.path);
257
257
  // Skip TS load attempt if JS TypeScript compilation not enabled and file is JS
258
258
  if (shouldTsIgnoreJs && /\.[cm]?js$/.test(request)) {
259
259
  return undefined;
@@ -262,7 +262,7 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
262
262
  // the options cannot change and do not need to be represented in the key. If the
263
263
  // cache is later stored to disk, then the options that affect transform output
264
264
  // would need to be added to the key as well as a check for any change of content.
265
- let contents = typeScriptFileCache.get((0, node_url_1.pathToFileURL)(request).href);
265
+ let contents = typeScriptFileCache.get(request);
266
266
  if (contents === undefined) {
267
267
  // If the Angular compilation had errors the file may not have been emitted.
268
268
  // To avoid additional errors about missing files, return empty contents.
@@ -285,28 +285,22 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
285
285
  // A string indicates untransformed output from the TS/NG compiler
286
286
  contents = await javascriptTransformer.transformData(request, contents, true /* skipLinker */);
287
287
  // Store as the returned Uint8Array to allow caching the fully transformed code
288
- typeScriptFileCache.set((0, node_url_1.pathToFileURL)(request).href, contents);
288
+ typeScriptFileCache.set(request, contents);
289
289
  }
290
290
  return {
291
291
  contents,
292
292
  loader: 'js',
293
293
  };
294
294
  });
295
- build.onLoad({ filter: /\.[cm]?js$/ }, (args) => (0, profiling_1.profileAsync)('NG_EMIT_JS*', async () => {
296
- // The filename is currently used as a cache key. Since the cache is memory only,
297
- // the options cannot change and do not need to be represented in the key. If the
298
- // cache is later stored to disk, then the options that affect transform output
299
- // would need to be added to the key as well as a check for any change of content.
300
- let contents = pluginOptions.sourceFileCache?.babelFileCache.get(args.path);
301
- if (contents === undefined) {
302
- contents = await javascriptTransformer.transformFile(args.path, pluginOptions.jit);
303
- pluginOptions.sourceFileCache?.babelFileCache.set(args.path, contents);
304
- }
305
- return {
306
- contents,
307
- loader: 'js',
308
- };
309
- }, true));
295
+ build.onLoad({ filter: /\.[cm]?js$/ }, (0, load_result_cache_1.createCachedLoad)(pluginOptions.loadResultCache, async (args) => {
296
+ return (0, profiling_1.profileAsync)('NG_EMIT_JS*', async () => {
297
+ const contents = await javascriptTransformer.transformFile(args.path, pluginOptions.jit);
298
+ return {
299
+ contents,
300
+ loader: 'js',
301
+ };
302
+ }, true);
303
+ }));
310
304
  // Setup bundling of component templates and stylesheets when in JIT mode
311
305
  if (pluginOptions.jit) {
312
306
  (0, jit_plugin_callbacks_1.setupJitPluginCallbacks)(build, stylesheetBundler, additionalResults, styleOptions.inlineStyleLanguage);
@@ -415,17 +409,19 @@ function bundleWebWorker(build, pluginOptions, workerFile) {
415
409
  }
416
410
  }
417
411
  function createMissingFileError(request, original, root) {
412
+ const relativeRequest = path.relative(root, request);
418
413
  const error = {
419
- text: `File '${path.relative(root, request)}' is missing from the TypeScript compilation.`,
414
+ text: `File '${relativeRequest}' is missing from the TypeScript compilation.`,
420
415
  notes: [
421
416
  {
422
417
  text: `Ensure the file is part of the TypeScript program via the 'files' or 'include' property.`,
423
418
  },
424
419
  ],
425
420
  };
426
- if (request !== original) {
421
+ const relativeOriginal = path.relative(root, original);
422
+ if (relativeRequest !== relativeOriginal) {
427
423
  error.notes.push({
428
- text: `File is requested from a file replacement of '${path.relative(root, original)}'.`,
424
+ text: `File is requested from a file replacement of '${relativeOriginal}'.`,
429
425
  });
430
426
  }
431
427
  return error;
@@ -8,23 +8,26 @@
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.FileReferenceTracker = void 0;
11
+ const node_path_1 = require("node:path");
11
12
  class FileReferenceTracker {
12
13
  #referencingFiles = new Map();
13
14
  get referencedFiles() {
14
15
  return this.#referencingFiles.keys();
15
16
  }
16
17
  add(containingFile, referencedFiles) {
18
+ const normalizedContainingFile = (0, node_path_1.normalize)(containingFile);
17
19
  for (const file of referencedFiles) {
18
- if (file === containingFile) {
20
+ const normalizedReferencedFile = (0, node_path_1.normalize)(file);
21
+ if (normalizedReferencedFile === normalizedContainingFile) {
19
22
  // Containing file is already known to the AOT compiler
20
23
  continue;
21
24
  }
22
- const referencing = this.#referencingFiles.get(file);
25
+ const referencing = this.#referencingFiles.get(normalizedReferencedFile);
23
26
  if (referencing === undefined) {
24
- this.#referencingFiles.set(file, new Set([containingFile]));
27
+ this.#referencingFiles.set(normalizedReferencedFile, new Set([normalizedContainingFile]));
25
28
  }
26
29
  else {
27
- referencing.add(containingFile);
30
+ referencing.add(normalizedContainingFile);
28
31
  }
29
32
  }
30
33
  }
@@ -37,14 +40,15 @@ class FileReferenceTracker {
37
40
  let allChangedFiles;
38
41
  // Add referencing files to fully notify the AOT compiler of required component updates
39
42
  for (const modifiedFile of changed) {
40
- const referencing = this.#referencingFiles.get(modifiedFile);
43
+ const normalizedModifiedFile = (0, node_path_1.normalize)(modifiedFile);
44
+ const referencing = this.#referencingFiles.get(normalizedModifiedFile);
41
45
  if (referencing) {
42
46
  allChangedFiles ??= new Set(changed);
43
47
  for (const referencingFile of referencing) {
44
48
  allChangedFiles.add(referencingFile);
45
49
  }
46
50
  // Cleanup the stale record which will be updated by new resource transforms
47
- this.#referencingFiles.delete(modifiedFile);
51
+ this.#referencingFiles.delete(normalizedModifiedFile);
48
52
  }
49
53
  }
50
54
  return allChangedFiles ?? changed;
@@ -10,7 +10,6 @@ import { MemoryLoadResultCache } from '../load-result-cache';
10
10
  export declare class SourceFileCache extends Map<string, ts.SourceFile> {
11
11
  readonly persistentCachePath?: string | undefined;
12
12
  readonly modifiedFiles: Set<string>;
13
- readonly babelFileCache: Map<string, Uint8Array>;
14
13
  readonly typeScriptFileCache: Map<string, string | Uint8Array>;
15
14
  readonly loadResultCache: MemoryLoadResultCache;
16
15
  referencedFiles?: readonly string[];
@@ -33,14 +33,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
33
33
  exports.SourceFileCache = void 0;
34
34
  const node_os_1 = require("node:os");
35
35
  const path = __importStar(require("node:path"));
36
- const node_url_1 = require("node:url");
37
36
  const load_result_cache_1 = require("../load-result-cache");
38
37
  const USING_WINDOWS = (0, node_os_1.platform)() === 'win32';
39
38
  const WINDOWS_SEP_REGEXP = new RegExp(`\\${path.win32.sep}`, 'g');
40
39
  class SourceFileCache extends Map {
41
40
  persistentCachePath;
42
41
  modifiedFiles = new Set();
43
- babelFileCache = new Map();
44
42
  typeScriptFileCache = new Map();
45
43
  loadResultCache = new load_result_cache_1.MemoryLoadResultCache();
46
44
  referencedFiles;
@@ -53,8 +51,8 @@ class SourceFileCache extends Map {
53
51
  this.modifiedFiles.clear();
54
52
  }
55
53
  for (let file of files) {
56
- this.babelFileCache.delete(file);
57
- this.typeScriptFileCache.delete((0, node_url_1.pathToFileURL)(file).href);
54
+ file = path.normalize(file);
55
+ this.typeScriptFileCache.delete(file);
58
56
  this.loadResultCache.invalidate(file);
59
57
  // Normalize separators to allow matching TypeScript Host paths
60
58
  if (USING_WINDOWS) {
@@ -8,6 +8,7 @@
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.ExecutionResult = void 0;
11
+ const node_path_1 = require("node:path");
11
12
  const utils_1 = require("./utils");
12
13
  /**
13
14
  * Represents the result of a single builder execute call.
@@ -57,11 +58,15 @@ class ExecutionResult {
57
58
  };
58
59
  }
59
60
  get watchFiles() {
61
+ // Bundler contexts internally normalize file dependencies
60
62
  const files = this.rebuildContexts.flatMap((context) => [...context.watchFiles]);
61
63
  if (this.codeBundleCache?.referencedFiles) {
62
- files.push(...this.codeBundleCache.referencedFiles);
64
+ // These files originate from TS/NG and can have POSIX path separators even on Windows.
65
+ // To ensure path comparisons are valid, all these paths must be normalized.
66
+ files.push(...this.codeBundleCache.referencedFiles.map(node_path_1.normalize));
63
67
  }
64
68
  if (this.codeBundleCache?.loadResultCache) {
69
+ // Load result caches internally normalize file dependencies
65
70
  files.push(...this.codeBundleCache.loadResultCache.watchFiles);
66
71
  }
67
72
  return files;
@@ -20,6 +20,11 @@ function createCachedLoad(cache, callback) {
20
20
  result = await callback(args);
21
21
  // Do not cache null or undefined
22
22
  if (result) {
23
+ // Ensure requested path is included if it was a resolved file
24
+ if (args.namespace === 'file') {
25
+ result.watchFiles ??= [];
26
+ result.watchFiles.push(args.path);
27
+ }
23
28
  await cache.put(loadCacheKey, result);
24
29
  }
25
30
  }
@@ -59,7 +64,9 @@ class MemoryLoadResultCache {
59
64
  return found;
60
65
  }
61
66
  get watchFiles() {
62
- return [...this.#loadResults.keys(), ...this.#fileDependencies.keys()];
67
+ // this.#loadResults.keys() is not included here because the keys
68
+ // are namespaced request paths and not disk-based file paths.
69
+ return [...this.#fileDependencies.keys()];
63
70
  }
64
71
  }
65
72
  exports.MemoryLoadResultCache = MemoryLoadResultCache;
@@ -50,6 +50,10 @@ let postcss;
50
50
  * Based on https://tailwindcss.com/docs/functions-and-directives
51
51
  */
52
52
  const TAILWIND_KEYWORDS = ['@tailwind', '@layer', '@apply', '@config', 'theme(', 'screen('];
53
+ /**
54
+ * Cached postcss instances that can be re-used between various StylesheetPluginFactory instances.
55
+ */
56
+ const postcssProcessor = new Map();
53
57
  class StylesheetPluginFactory {
54
58
  options;
55
59
  cache;
@@ -73,9 +77,15 @@ class StylesheetPluginFactory {
73
77
  return this.postcssProcessor;
74
78
  }
75
79
  if (options.tailwindConfiguration) {
76
- postcss ??= (await Promise.resolve().then(() => __importStar(require('postcss')))).default;
77
- const tailwind = await Promise.resolve(`${options.tailwindConfiguration.package}`).then(s => __importStar(require(s)));
78
- this.postcssProcessor = postcss().use(tailwind.default({ config: options.tailwindConfiguration.file }));
80
+ const { package: tailwindPackage, file: config } = options.tailwindConfiguration;
81
+ const postCssInstanceKey = tailwindPackage + ':' + config;
82
+ this.postcssProcessor = postcssProcessor.get(postCssInstanceKey)?.deref();
83
+ if (!this.postcssProcessor) {
84
+ postcss ??= (await Promise.resolve().then(() => __importStar(require('postcss')))).default;
85
+ const tailwind = await Promise.resolve(`${tailwindPackage}`).then(s => __importStar(require(s)));
86
+ this.postcssProcessor = postcss().use(tailwind.default({ config }));
87
+ postcssProcessor.set(postCssInstanceKey, new WeakRef(this.postcssProcessor));
88
+ }
79
89
  }
80
90
  return this.postcssProcessor;
81
91
  };
@@ -81,5 +81,8 @@ exports.useLegacySass = (() => {
81
81
  })();
82
82
  const debugPerfVariable = process.env['NG_BUILD_DEBUG_PERF'];
83
83
  exports.debugPerformance = isPresent(debugPerfVariable) && isEnabled(debugPerfVariable);
84
+ // Default to true on Windows to workaround Visual Studio atomic file saving watch issues
84
85
  const watchRootVariable = process.env['NG_BUILD_WATCH_ROOT'];
85
- exports.shouldWatchRoot = isPresent(watchRootVariable) && isEnabled(watchRootVariable);
86
+ exports.shouldWatchRoot = process.platform === 'win32'
87
+ ? !isPresent(watchRootVariable) || !isDisabled(watchRootVariable)
88
+ : isPresent(watchRootVariable) && isEnabled(watchRootVariable);
@@ -1,7 +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
- */
@@ -1,41 +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
- // import { AngularCompilation, createAngularCompilation } from './compilation';
10
- // import { ComponentStylesheetBundler } from './component-stylesheets';
11
- // export interface InvalidationResult {
12
- // code: boolean;
13
- // styles: string[];
14
- // }
15
- // export class ApplicationAngularCompiler {
16
- // #compilation: AngularCompilation | undefined;
17
- // #stylesheetBundler: ComponentStylesheetBundler;
18
- // readonly #emitFileCache = new Map<string, string>();
19
- // constructor(options: { persistentCachePath?: string; jitMode?: boolean, incremental?: boolean }) {
20
- // const {
21
- // jitMode = false,
22
- // incremental = false,
23
- // persistentCachePath,
24
- // } = options;
25
- // this.#stylesheetBundler = new ComponentStylesheetBundler({}, incremental);
26
- // }
27
- // get isJit(): boolean {
28
- // return false;
29
- // }
30
- // get usesAllowJs(): boolean {
31
- // return false;
32
- // }
33
- // async initialize() {
34
- // }
35
- // invalidate(files: Iterable<string>): InvalidationResult {
36
- // return {
37
- // code: true,
38
- // styles: [],
39
- // };
40
- // }
41
- // }