@angular/build 21.0.0-next.0 → 21.0.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular/build",
3
- "version": "21.0.0-next.0",
3
+ "version": "21.0.0-next.1",
4
4
  "description": "Official build system for Angular",
5
5
  "keywords": [
6
6
  "Angular CLI",
@@ -23,11 +23,11 @@
23
23
  "builders": "builders.json",
24
24
  "dependencies": {
25
25
  "@ampproject/remapping": "2.3.0",
26
- "@angular-devkit/architect": "0.2100.0-next.0",
26
+ "@angular-devkit/architect": "0.2100.0-next.1",
27
27
  "@babel/core": "7.28.3",
28
28
  "@babel/helper-annotate-as-pure": "7.27.3",
29
29
  "@babel/helper-split-export-declaration": "7.24.7",
30
- "@inquirer/confirm": "5.1.15",
30
+ "@inquirer/confirm": "5.1.16",
31
31
  "@vitejs/plugin-basic-ssl": "2.1.0",
32
32
  "beasties": "0.3.5",
33
33
  "browserslist": "^4.23.0",
@@ -35,14 +35,14 @@
35
35
  "https-proxy-agent": "7.0.6",
36
36
  "istanbul-lib-instrument": "6.0.3",
37
37
  "jsonc-parser": "3.3.1",
38
- "listr2": "9.0.1",
39
- "magic-string": "0.30.17",
38
+ "listr2": "9.0.2",
39
+ "magic-string": "0.30.18",
40
40
  "mrmime": "2.0.1",
41
41
  "parse5-html-rewriting-stream": "8.0.0",
42
42
  "picomatch": "4.0.3",
43
43
  "piscina": "5.1.3",
44
- "rolldown": "1.0.0-beta.33",
45
- "sass": "1.90.0",
44
+ "rolldown": "1.0.0-beta.34",
45
+ "sass": "1.91.0",
46
46
  "semver": "7.7.2",
47
47
  "source-map-support": "0.5.21",
48
48
  "tinyglobby": "0.2.14",
@@ -60,7 +60,7 @@
60
60
  "@angular/platform-browser": "^21.0.0-next.0",
61
61
  "@angular/platform-server": "^21.0.0-next.0",
62
62
  "@angular/service-worker": "^21.0.0-next.0",
63
- "@angular/ssr": "^21.0.0-next.0",
63
+ "@angular/ssr": "^21.0.0-next.1",
64
64
  "karma": "^6.4.0",
65
65
  "less": "^4.2.0",
66
66
  "ng-packagr": "^21.0.0-next.0",
@@ -198,7 +198,8 @@ async function optimizeChunks(original, sourcemap) {
198
198
  ],
199
199
  });
200
200
  const result = await bundle.generate({
201
- minify: { mangle: false, compress: false, removeWhitespace: true },
201
+ minify: { mangle: false, compress: false },
202
+ advancedChunks: { minSize: 8192 },
202
203
  sourcemap,
203
204
  chunkFileNames: (chunkInfo) => `${chunkInfo.name.replace(/-[a-zA-Z0-9]{8}$/, '')}-[hash].js`,
204
205
  });
@@ -170,6 +170,8 @@ class AngularPolyfillsPlugin {
170
170
  included: true,
171
171
  watched: false,
172
172
  });
173
+ // Karma needs a return value for a factory and Karma's multi-reporter expects an `adapters` array
174
+ return { adapters: [] };
173
175
  }, AngularPolyfillsPlugin),
174
176
  ],
175
177
  };
@@ -6,7 +6,7 @@
6
6
  * found in the LICENSE file at https://angular.dev/license
7
7
  */
8
8
  import type { BuilderOutput } from '@angular-devkit/architect';
9
- import type { FullResult, IncrementalResult } from '../../../application/results';
9
+ import { type FullResult, type IncrementalResult } from '../../../application/results';
10
10
  import { NormalizedUnitTestBuilderOptions } from '../../options';
11
11
  import type { TestExecutor } from '../api';
12
12
  export declare class VitestExecutor implements TestExecutor {
@@ -15,6 +15,7 @@ export declare class VitestExecutor implements TestExecutor {
15
15
  private readonly options;
16
16
  private readonly outputPath;
17
17
  private latestBuildResult;
18
+ private readonly sigintListener;
18
19
  constructor(projectName: string, options: NormalizedUnitTestBuilderOptions);
19
20
  execute(buildResult: FullResult | IncrementalResult): AsyncIterable<BuilderOutput>;
20
21
  [Symbol.asyncDispose](): Promise<void>;
@@ -13,10 +13,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.VitestExecutor = void 0;
14
14
  const node_assert_1 = __importDefault(require("node:assert"));
15
15
  const node_crypto_1 = require("node:crypto");
16
+ const node_fs_1 = require("node:fs");
17
+ const promises_1 = require("node:fs/promises");
16
18
  const node_path_1 = __importDefault(require("node:path"));
17
19
  const error_1 = require("../../../../utils/error");
18
20
  const load_esm_1 = require("../../../../utils/load-esm");
19
21
  const path_1 = require("../../../../utils/path");
22
+ const results_1 = require("../../../application/results");
20
23
  const application_builder_1 = require("../../../karma/application_builder");
21
24
  const browser_provider_1 = require("./browser-provider");
22
25
  class VitestExecutor {
@@ -25,24 +28,56 @@ class VitestExecutor {
25
28
  options;
26
29
  outputPath;
27
30
  latestBuildResult;
31
+ // Graceful shutdown signal handler
32
+ // This is needed to remove the temporary output directory on Ctrl+C
33
+ sigintListener = () => {
34
+ (0, node_fs_1.rmSync)(this.outputPath, { recursive: true, force: true });
35
+ };
28
36
  constructor(projectName, options) {
29
37
  this.projectName = projectName;
30
38
  this.options = options;
31
39
  this.outputPath = (0, path_1.toPosixPath)(node_path_1.default.join(options.workspaceRoot, generateOutputPath()));
40
+ process.on('SIGINT', this.sigintListener);
32
41
  }
33
42
  async *execute(buildResult) {
34
43
  await (0, application_builder_1.writeTestFiles)(buildResult.files, this.outputPath);
35
44
  this.latestBuildResult = buildResult;
45
+ // Initialize Vitest if not already present.
36
46
  this.vitest ??= await this.initializeVitest();
47
+ const vitest = this.vitest;
48
+ let testResults;
49
+ if (buildResult.kind === results_1.ResultKind.Incremental) {
50
+ const addedFiles = buildResult.added.map((file) => node_path_1.default.join(this.outputPath, file));
51
+ const modifiedFiles = buildResult.modified.map((file) => node_path_1.default.join(this.outputPath, file));
52
+ if (addedFiles.length === 0 && modifiedFiles.length === 0) {
53
+ yield { success: true };
54
+ return;
55
+ }
56
+ // If new files are added, use `start` to trigger test discovery.
57
+ // Also pass modified files to `start` to ensure they are re-run.
58
+ if (addedFiles.length > 0) {
59
+ await vitest.start([...addedFiles, ...modifiedFiles]);
60
+ }
61
+ else {
62
+ // For modified files only, use the more efficient `rerunTestSpecifications`
63
+ const specsToRerun = modifiedFiles.flatMap((file) => vitest.getModuleSpecifications(file));
64
+ if (specsToRerun.length > 0) {
65
+ modifiedFiles.forEach((file) => vitest.invalidateFile(file));
66
+ testResults = await vitest.rerunTestSpecifications(specsToRerun);
67
+ }
68
+ }
69
+ }
37
70
  // Check if all the tests pass to calculate the result
38
- const testModules = this.vitest.state.getTestModules();
39
- yield { success: testModules.every((testModule) => testModule.ok()) };
71
+ const testModules = testResults?.testModules;
72
+ yield { success: testModules?.every((testModule) => testModule.ok()) ?? true };
40
73
  }
41
74
  async [Symbol.asyncDispose]() {
75
+ process.off('SIGINT', this.sigintListener);
42
76
  await this.vitest?.close();
77
+ await (0, promises_1.rm)(this.outputPath, { recursive: true, force: true });
43
78
  }
44
79
  async initializeVitest() {
45
- const { codeCoverage, reporters, watch, workspaceRoot, setupFiles, browsers, debug } = this.options;
80
+ const { codeCoverage, reporters, workspaceRoot, setupFiles, browsers, debug, watch } = this.options;
46
81
  const { outputPath, projectName, latestBuildResult } = this;
47
82
  let vitestNodeModule;
48
83
  try {
@@ -76,7 +111,7 @@ class VitestExecutor {
76
111
  fileParallelism: false,
77
112
  }
78
113
  : {};
79
- return startVitest('test', undefined /* cliFilters */, {
114
+ return startVitest('test', undefined, {
80
115
  // Disable configuration file resolution/loading
81
116
  config: false,
82
117
  root: workspaceRoot,
@@ -88,6 +123,11 @@ class VitestExecutor {
88
123
  coverage: generateCoverageOption(codeCoverage, workspaceRoot, this.outputPath),
89
124
  ...debugOptions,
90
125
  }, {
126
+ server: {
127
+ // Disable the actual file watcher. The boolean watch option above should still
128
+ // be enabled as it controls other internal behavior related to rerunning tests.
129
+ watch: null,
130
+ },
91
131
  plugins: [
92
132
  {
93
133
  name: 'angular:project-init',
@@ -55,6 +55,7 @@ const profiling_1 = require("../profiling");
55
55
  const compilation_state_1 = require("./compilation-state");
56
56
  const file_reference_tracker_1 = require("./file-reference-tracker");
57
57
  const jit_plugin_callbacks_1 = require("./jit-plugin-callbacks");
58
+ const rewrite_bazel_paths_1 = require("./rewrite-bazel-paths");
58
59
  // eslint-disable-next-line max-lines-per-function
59
60
  function createCompilerPlugin(pluginOptions, compilationOrFactory, stylesheetBundler) {
60
61
  return {
@@ -321,7 +322,7 @@ function createCompilerPlugin(pluginOptions, compilationOrFactory, stylesheetBun
321
322
  return result;
322
323
  });
323
324
  build.onLoad({ filter: /\.[cm]?[jt]sx?$/ }, async (args) => {
324
- const request = path.normalize(pluginOptions.fileReplacements?.[path.normalize(args.path)] ?? args.path);
325
+ const request = (0, rewrite_bazel_paths_1.rewriteForBazel)(path.normalize(pluginOptions.fileReplacements?.[path.normalize(args.path)] ?? args.path));
325
326
  const isJS = /\.[cm]?js$/.test(request);
326
327
  // Skip TS load attempt if JS TypeScript compilation not enabled and file is JS
327
328
  if (shouldTsIgnoreJs && isJS) {
@@ -375,10 +376,11 @@ function createCompilerPlugin(pluginOptions, compilationOrFactory, stylesheetBun
375
376
  return {
376
377
  contents,
377
378
  loader,
379
+ resolveDir: path.dirname(request),
378
380
  };
379
381
  });
380
382
  build.onLoad({ filter: /\.[cm]?js$/ }, (0, load_result_cache_1.createCachedLoad)(pluginOptions.loadResultCache, async (args) => {
381
- let request = args.path;
383
+ let request = (0, rewrite_bazel_paths_1.rewriteForBazel)(args.path);
382
384
  if (pluginOptions.fileReplacements) {
383
385
  const replacement = pluginOptions.fileReplacements[path.normalize(args.path)];
384
386
  if (replacement) {
@@ -391,6 +393,7 @@ function createCompilerPlugin(pluginOptions, compilationOrFactory, stylesheetBun
391
393
  return {
392
394
  contents,
393
395
  loader: 'js',
396
+ resolveDir: path.dirname(request),
394
397
  watchFiles: request !== args.path ? [request] : undefined,
395
398
  };
396
399
  }, true);
@@ -0,0 +1,8 @@
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
+ export declare function rewriteForBazel(path: string): string;
@@ -0,0 +1,27 @@
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.dev/license
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.rewriteForBazel = rewriteForBazel;
11
+ const node_path_1 = require("node:path");
12
+ const bazelBinDirectory = process.env['BAZEL_BINDIR'];
13
+ const bazelExecRoot = process.env['JS_BINARY__EXECROOT'];
14
+ function rewriteForBazel(path) {
15
+ if (!bazelBinDirectory || !bazelExecRoot) {
16
+ return path;
17
+ }
18
+ const fromExecRoot = (0, node_path_1.relative)(bazelExecRoot, path);
19
+ if (!fromExecRoot.startsWith('..')) {
20
+ return path;
21
+ }
22
+ const fromBinDirectory = (0, node_path_1.relative)(bazelBinDirectory, path);
23
+ if (fromBinDirectory.startsWith('..')) {
24
+ return path;
25
+ }
26
+ return (0, node_path_1.join)(bazelExecRoot, fromBinDirectory);
27
+ }
@@ -10,7 +10,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.normalizeCacheOptions = normalizeCacheOptions;
11
11
  const node_path_1 = require("node:path");
12
12
  /** Version placeholder is replaced during the build process with actual package version */
13
- const VERSION = '21.0.0-next.0';
13
+ const VERSION = '21.0.0-next.1';
14
14
  function hasCacheMetadata(value) {
15
15
  return (!!value &&
16
16
  typeof value === 'object' &&