@angular/build 20.2.0-next.0 → 20.2.0-next.2
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 +9 -9
- package/src/builders/application/chunk-optimizer.js +3 -3
- package/src/builders/unit-test/builder.js +9 -1
- package/src/builders/unit-test/schema.d.ts +2 -1
- package/src/builders/unit-test/schema.json +1 -1
- package/src/tools/vite/middlewares/assets-middleware.js +35 -16
- package/src/tools/vite/plugins/ssr-transform-plugin.js +1 -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": "20.2.0-next.
|
|
3
|
+
"version": "20.2.0-next.2",
|
|
4
4
|
"description": "Official build system for Angular",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Angular CLI",
|
|
@@ -23,15 +23,15 @@
|
|
|
23
23
|
"builders": "builders.json",
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@ampproject/remapping": "2.3.0",
|
|
26
|
-
"@angular-devkit/architect": "0.2002.0-next.
|
|
26
|
+
"@angular-devkit/architect": "0.2002.0-next.2",
|
|
27
27
|
"@babel/core": "7.28.0",
|
|
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.14",
|
|
31
31
|
"@vitejs/plugin-basic-ssl": "2.1.0",
|
|
32
32
|
"beasties": "0.3.5",
|
|
33
33
|
"browserslist": "^4.23.0",
|
|
34
|
-
"esbuild": "0.25.
|
|
34
|
+
"esbuild": "0.25.8",
|
|
35
35
|
"https-proxy-agent": "7.0.6",
|
|
36
36
|
"istanbul-lib-instrument": "6.0.3",
|
|
37
37
|
"jsonc-parser": "3.3.1",
|
|
@@ -39,14 +39,14 @@
|
|
|
39
39
|
"magic-string": "0.30.17",
|
|
40
40
|
"mrmime": "2.0.1",
|
|
41
41
|
"parse5-html-rewriting-stream": "8.0.0",
|
|
42
|
-
"picomatch": "4.0.
|
|
42
|
+
"picomatch": "4.0.3",
|
|
43
43
|
"piscina": "5.1.3",
|
|
44
|
-
"
|
|
44
|
+
"rolldown": "1.0.0-beta.29",
|
|
45
45
|
"sass": "1.89.2",
|
|
46
46
|
"semver": "7.7.2",
|
|
47
47
|
"source-map-support": "0.5.21",
|
|
48
48
|
"tinyglobby": "0.2.14",
|
|
49
|
-
"vite": "7.0.
|
|
49
|
+
"vite": "7.0.6",
|
|
50
50
|
"watchpack": "2.4.4"
|
|
51
51
|
},
|
|
52
52
|
"optionalDependencies": {
|
|
@@ -60,14 +60,14 @@
|
|
|
60
60
|
"@angular/platform-browser": "^20.0.0 || ^20.2.0-next.0",
|
|
61
61
|
"@angular/platform-server": "^20.0.0 || ^20.2.0-next.0",
|
|
62
62
|
"@angular/service-worker": "^20.0.0 || ^20.2.0-next.0",
|
|
63
|
-
"@angular/ssr": "^20.2.0-next.
|
|
63
|
+
"@angular/ssr": "^20.2.0-next.2",
|
|
64
64
|
"karma": "^6.4.0",
|
|
65
65
|
"less": "^4.2.0",
|
|
66
66
|
"ng-packagr": "^20.0.0 || ^20.2.0-next.0",
|
|
67
67
|
"postcss": "^8.4.0",
|
|
68
68
|
"tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0",
|
|
69
69
|
"tslib": "^2.3.0",
|
|
70
|
-
"typescript": ">=5.8 <
|
|
70
|
+
"typescript": ">=5.8 <6.0",
|
|
71
71
|
"vitest": "^3.1.1"
|
|
72
72
|
},
|
|
73
73
|
"peerDependenciesMeta": {
|
|
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
13
|
exports.optimizeChunks = optimizeChunks;
|
|
14
14
|
const node_assert_1 = __importDefault(require("node:assert"));
|
|
15
|
-
const
|
|
15
|
+
const rolldown_1 = require("rolldown");
|
|
16
16
|
const bundler_context_1 = require("../../tools/esbuild/bundler-context");
|
|
17
17
|
const utils_1 = require("../../tools/esbuild/utils");
|
|
18
18
|
const error_1 = require("../../utils/error");
|
|
@@ -54,7 +54,7 @@ async function optimizeChunks(original, sourcemap) {
|
|
|
54
54
|
let bundle;
|
|
55
55
|
let optimizedOutput;
|
|
56
56
|
try {
|
|
57
|
-
bundle = await (0,
|
|
57
|
+
bundle = await (0, rolldown_1.rolldown)({
|
|
58
58
|
input: mainFile,
|
|
59
59
|
plugins: [
|
|
60
60
|
{
|
|
@@ -81,7 +81,7 @@ async function optimizeChunks(original, sourcemap) {
|
|
|
81
81
|
],
|
|
82
82
|
});
|
|
83
83
|
const result = await bundle.generate({
|
|
84
|
-
|
|
84
|
+
minify: { mangle: false, compress: false, removeWhitespace: true },
|
|
85
85
|
sourcemap,
|
|
86
86
|
chunkFileNames: (chunkInfo) => `${chunkInfo.name.replace(/-[a-zA-Z0-9]{8}$/, '')}-[hash].js`,
|
|
87
87
|
});
|
|
@@ -256,6 +256,13 @@ function findBrowserProvider(projectResolver) {
|
|
|
256
256
|
catch { }
|
|
257
257
|
}
|
|
258
258
|
}
|
|
259
|
+
function normalizeBrowserName(browserName) {
|
|
260
|
+
// Normalize browser names to match Vitest's expectations for headless but also supports karma's names
|
|
261
|
+
// e.g., 'ChromeHeadless' -> 'chrome', 'FirefoxHeadless'
|
|
262
|
+
// and 'Chrome' -> 'chrome', 'Firefox' -> 'firefox'.
|
|
263
|
+
const normalized = browserName.toLowerCase();
|
|
264
|
+
return normalized.replace(/headless$/, '');
|
|
265
|
+
}
|
|
259
266
|
function setupBrowserConfiguration(browsers, debug, projectSourceRoot) {
|
|
260
267
|
if (browsers === undefined) {
|
|
261
268
|
return {};
|
|
@@ -288,8 +295,9 @@ function setupBrowserConfiguration(browsers, debug, projectSourceRoot) {
|
|
|
288
295
|
const browser = {
|
|
289
296
|
enabled: true,
|
|
290
297
|
provider,
|
|
298
|
+
headless: browsers.some((name) => name.toLowerCase().includes('headless')),
|
|
291
299
|
instances: browsers.map((browserName) => ({
|
|
292
|
-
browser: browserName,
|
|
300
|
+
browser: normalizeBrowserName(browserName),
|
|
293
301
|
})),
|
|
294
302
|
};
|
|
295
303
|
return { browser };
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
export type Schema = {
|
|
5
5
|
/**
|
|
6
6
|
* A list of browsers to use for test execution. If undefined, jsdom on Node.js will be used
|
|
7
|
-
* instead of a browser.
|
|
7
|
+
* instead of a browser. For Vitest and Karma, browser names ending with 'Headless' (e.g.,
|
|
8
|
+
* 'ChromeHeadless') will enable headless mode for that browser.
|
|
8
9
|
*/
|
|
9
10
|
browsers?: string[];
|
|
10
11
|
/**
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"enum": ["karma", "vitest"]
|
|
20
20
|
},
|
|
21
21
|
"browsers": {
|
|
22
|
-
"description": "A list of browsers to use for test execution. If undefined, jsdom on Node.js will be used instead of a browser.",
|
|
22
|
+
"description": "A list of browsers to use for test execution. If undefined, jsdom on Node.js will be used instead of a browser. For Vitest and Karma, browser names ending with 'Headless' (e.g., 'ChromeHeadless') will enable headless mode for that browser.",
|
|
23
23
|
"type": "array",
|
|
24
24
|
"items": {
|
|
25
25
|
"type": "string"
|
|
@@ -9,8 +9,12 @@
|
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.createAngularAssetsMiddleware = createAngularAssetsMiddleware;
|
|
11
11
|
const mrmime_1 = require("mrmime");
|
|
12
|
+
const node_crypto_1 = require("node:crypto");
|
|
13
|
+
const node_fs_1 = require("node:fs");
|
|
12
14
|
const node_path_1 = require("node:path");
|
|
13
15
|
const utils_1 = require("../utils");
|
|
16
|
+
const CSS_PREPROCESSOR_REGEXP = /\.(?:s[ac]ss|less|css)$/;
|
|
17
|
+
const JS_TS_REGEXP = /\.[cm]?[tj]sx?$/;
|
|
14
18
|
function createAngularAssetsMiddleware(server, assets, outputFiles, componentStyles, encapsulateStyle) {
|
|
15
19
|
return function angularAssetsMiddleware(req, res, next) {
|
|
16
20
|
if (req.url === undefined || res.writableEnded) {
|
|
@@ -24,14 +28,27 @@ function createAngularAssetsMiddleware(server, assets, outputFiles, componentSty
|
|
|
24
28
|
// Rewrite all build assets to a vite raw fs URL
|
|
25
29
|
const asset = assets.get(pathname);
|
|
26
30
|
if (asset) {
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
// This is a workaround to serve CSS, JS and TS files without Vite transformations.
|
|
32
|
+
if (JS_TS_REGEXP.test(extension) || CSS_PREPROCESSOR_REGEXP.test(extension)) {
|
|
33
|
+
const contents = (0, node_fs_1.readFileSync)(asset.source);
|
|
34
|
+
const etag = `W/${(0, node_crypto_1.createHash)('sha256').update(contents).digest('hex')}`;
|
|
35
|
+
if (checkAndHandleEtag(req, res, etag)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const mimeType = (0, mrmime_1.lookup)(extension);
|
|
39
|
+
if (mimeType) {
|
|
40
|
+
res.setHeader('Content-Type', mimeType);
|
|
41
|
+
}
|
|
42
|
+
res.setHeader('ETag', etag);
|
|
43
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
44
|
+
res.end(contents);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// The encoding needs to match what happens in the vite static middleware.
|
|
48
|
+
// ref: https://github.com/vitejs/vite/blob/d4f13bd81468961c8c926438e815ab6b1c82735e/packages/vite/src/node/server/middlewares/static.ts#L163
|
|
49
|
+
req.url = `${server.config.base}@fs/${encodeURI(asset.source)}`;
|
|
50
|
+
next();
|
|
51
|
+
}
|
|
35
52
|
return;
|
|
36
53
|
}
|
|
37
54
|
// HTML fallbacking
|
|
@@ -78,11 +95,8 @@ function createAngularAssetsMiddleware(server, assets, outputFiles, componentSty
|
|
|
78
95
|
else {
|
|
79
96
|
componentStyle.used.add(componentId);
|
|
80
97
|
}
|
|
81
|
-
// Report if there are no changes to avoid reprocessing
|
|
82
98
|
const etag = `W/"${outputFile.contents.byteLength}-${outputFile.hash}-${componentId}"`;
|
|
83
|
-
if (req
|
|
84
|
-
res.statusCode = 304;
|
|
85
|
-
res.end();
|
|
99
|
+
if (checkAndHandleEtag(req, res, etag)) {
|
|
86
100
|
return;
|
|
87
101
|
}
|
|
88
102
|
// Shim the stylesheet if a component ID is provided
|
|
@@ -105,11 +119,8 @@ function createAngularAssetsMiddleware(server, assets, outputFiles, componentSty
|
|
|
105
119
|
return;
|
|
106
120
|
}
|
|
107
121
|
}
|
|
108
|
-
// Avoid resending the content if it has not changed since last request
|
|
109
122
|
const etag = `W/"${outputFile.contents.byteLength}-${outputFile.hash}"`;
|
|
110
|
-
if (req
|
|
111
|
-
res.statusCode = 304;
|
|
112
|
-
res.end();
|
|
123
|
+
if (checkAndHandleEtag(req, res, etag)) {
|
|
113
124
|
return;
|
|
114
125
|
}
|
|
115
126
|
const mimeType = (0, mrmime_1.lookup)(extension);
|
|
@@ -152,3 +163,11 @@ function createAngularAssetsMiddleware(server, assets, outputFiles, componentSty
|
|
|
152
163
|
next();
|
|
153
164
|
};
|
|
154
165
|
}
|
|
166
|
+
function checkAndHandleEtag(req, res, etag) {
|
|
167
|
+
if (req.headers['if-none-match'] === etag) {
|
|
168
|
+
res.statusCode = 304;
|
|
169
|
+
res.end();
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
@@ -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 = '20.2.0-next.
|
|
13
|
+
const VERSION = '20.2.0-next.2';
|
|
14
14
|
function hasCacheMetadata(value) {
|
|
15
15
|
return (!!value &&
|
|
16
16
|
typeof value === 'object' &&
|