@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 +8 -8
- package/src/builders/application/chunk-optimizer.js +2 -1
- package/src/builders/karma/application_builder.js +2 -0
- package/src/builders/unit-test/runners/vitest/executor.d.ts +2 -1
- package/src/builders/unit-test/runners/vitest/executor.js +44 -4
- package/src/tools/esbuild/angular/compiler-plugin.js +5 -2
- package/src/tools/esbuild/angular/rewrite-bazel-paths.d.ts +8 -0
- package/src/tools/esbuild/angular/rewrite-bazel-paths.js +27 -0
- package/src/utils/normalize-cache.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@angular/build",
|
|
3
|
-
"version": "21.0.0-next.
|
|
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.
|
|
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.
|
|
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.
|
|
39
|
-
"magic-string": "0.30.
|
|
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.
|
|
45
|
-
"sass": "1.
|
|
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.
|
|
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
|
|
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
|
|
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 =
|
|
39
|
-
yield { success: testModules
|
|
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,
|
|
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
|
|
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.
|
|
13
|
+
const VERSION = '21.0.0-next.1';
|
|
14
14
|
function hasCacheMetadata(value) {
|
|
15
15
|
return (!!value &&
|
|
16
16
|
typeof value === 'object' &&
|