@angular/build 20.0.0-next.3 → 20.0.0-next.4
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 +7 -8
- package/src/builders/application/options.d.ts +2 -0
- package/src/builders/application/options.js +29 -6
- package/src/builders/application/schema.d.ts +14 -4
- package/src/builders/application/schema.json +8 -2
- package/src/builders/dev-server/vite-server.js +0 -6
- package/src/builders/karma/application_builder.js +9 -0
- package/src/builders/karma/index.js +1 -1
- package/src/builders/karma/polyfills/init_test_bed.js +2 -4
- package/src/tools/esbuild/application-code-bundle.js +25 -7
- package/src/tools/esbuild/javascript-transformer-worker.js +1 -3
- 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.0.0-next.
|
|
3
|
+
"version": "20.0.0-next.4",
|
|
4
4
|
"description": "Official build system for Angular",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Angular CLI",
|
|
@@ -23,16 +23,15 @@
|
|
|
23
23
|
"builders": "builders.json",
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@ampproject/remapping": "2.3.0",
|
|
26
|
-
"@angular-devkit/architect": "0.2000.0-next.
|
|
26
|
+
"@angular-devkit/architect": "0.2000.0-next.4",
|
|
27
27
|
"@babel/core": "7.26.10",
|
|
28
28
|
"@babel/helper-annotate-as-pure": "7.25.9",
|
|
29
29
|
"@babel/helper-split-export-declaration": "7.24.7",
|
|
30
|
-
"@babel/plugin-syntax-import-attributes": "7.26.0",
|
|
31
30
|
"@inquirer/confirm": "5.1.8",
|
|
32
31
|
"@vitejs/plugin-basic-ssl": "2.0.0",
|
|
33
32
|
"beasties": "0.2.0",
|
|
34
33
|
"browserslist": "^4.23.0",
|
|
35
|
-
"esbuild": "0.25.
|
|
34
|
+
"esbuild": "0.25.2",
|
|
36
35
|
"https-proxy-agent": "7.0.6",
|
|
37
36
|
"istanbul-lib-instrument": "6.0.3",
|
|
38
37
|
"jsonc-parser": "3.3.1",
|
|
@@ -42,12 +41,12 @@
|
|
|
42
41
|
"parse5-html-rewriting-stream": "7.0.0",
|
|
43
42
|
"picomatch": "4.0.2",
|
|
44
43
|
"piscina": "4.9.2",
|
|
45
|
-
"rollup": "4.
|
|
46
|
-
"sass": "1.86.
|
|
44
|
+
"rollup": "4.39.0",
|
|
45
|
+
"sass": "1.86.1",
|
|
47
46
|
"semver": "7.7.1",
|
|
48
47
|
"source-map-support": "0.5.21",
|
|
49
48
|
"tinyglobby": "0.2.12",
|
|
50
|
-
"vite": "6.2.
|
|
49
|
+
"vite": "6.2.4",
|
|
51
50
|
"watchpack": "2.4.2"
|
|
52
51
|
},
|
|
53
52
|
"optionalDependencies": {
|
|
@@ -60,7 +59,7 @@
|
|
|
60
59
|
"@angular/platform-browser": "^20.0.0 || ^20.0.0-next.0",
|
|
61
60
|
"@angular/platform-server": "^20.0.0 || ^20.0.0-next.0",
|
|
62
61
|
"@angular/service-worker": "^20.0.0 || ^20.0.0-next.0",
|
|
63
|
-
"@angular/ssr": "^20.0.0-next.
|
|
62
|
+
"@angular/ssr": "^20.0.0-next.4",
|
|
64
63
|
"karma": "^6.4.0",
|
|
65
64
|
"less": "^4.2.0",
|
|
66
65
|
"ng-packagr": "^20.0.0 || ^20.0.0-next.0",
|
|
@@ -203,6 +203,8 @@ export declare function normalizeOptions(context: BuilderContext, projectName: s
|
|
|
203
203
|
};
|
|
204
204
|
templateUpdates: boolean;
|
|
205
205
|
incrementalResults: boolean;
|
|
206
|
+
customConditions: string[] | undefined;
|
|
207
|
+
frameworkVersion: string;
|
|
206
208
|
}>;
|
|
207
209
|
export declare function getLocaleBaseHref(baseHref: string | undefined, i18n: NormalizedApplicationBuildOptions['i18nOptions'], locale: string): string | undefined;
|
|
208
210
|
export {};
|
|
@@ -132,12 +132,12 @@ async function normalizeOptions(context, projectName, options, extensions) {
|
|
|
132
132
|
? undefined
|
|
133
133
|
: await getTailwindConfig(searchDirectories, workspaceRoot, context);
|
|
134
134
|
let serverEntryPoint;
|
|
135
|
-
if (options.server) {
|
|
135
|
+
if (typeof options.server === 'string') {
|
|
136
|
+
if (options.server === '') {
|
|
137
|
+
throw new Error('The "server" option cannot be an empty string.');
|
|
138
|
+
}
|
|
136
139
|
serverEntryPoint = node_path_1.default.join(workspaceRoot, options.server);
|
|
137
140
|
}
|
|
138
|
-
else if (options.server === '') {
|
|
139
|
-
throw new Error('The "server" option cannot be an empty string.');
|
|
140
|
-
}
|
|
141
141
|
let prerenderOptions;
|
|
142
142
|
if (options.prerender) {
|
|
143
143
|
const { discoverRoutes = true, routesFile = undefined } = options.prerender === true ? {} : options.prerender;
|
|
@@ -191,12 +191,18 @@ async function normalizeOptions(context, projectName, options, extensions) {
|
|
|
191
191
|
let indexHtmlOptions;
|
|
192
192
|
// index can never have a value of `true` but in the schema it's of type `boolean`.
|
|
193
193
|
if (typeof options.index !== 'boolean') {
|
|
194
|
+
let indexInput;
|
|
194
195
|
let indexOutput;
|
|
195
196
|
// The output file will be created within the configured output path
|
|
196
197
|
if (typeof options.index === 'string') {
|
|
197
|
-
indexOutput = options.index;
|
|
198
|
+
indexInput = indexOutput = node_path_1.default.join(workspaceRoot, options.index);
|
|
199
|
+
}
|
|
200
|
+
else if (typeof options.index === 'undefined') {
|
|
201
|
+
indexInput = node_path_1.default.join(projectSourceRoot, 'index.html');
|
|
202
|
+
indexOutput = 'index.html';
|
|
198
203
|
}
|
|
199
204
|
else {
|
|
205
|
+
indexInput = node_path_1.default.join(workspaceRoot, options.index.input);
|
|
200
206
|
indexOutput = options.index.output || 'index.html';
|
|
201
207
|
}
|
|
202
208
|
/**
|
|
@@ -214,7 +220,7 @@ async function normalizeOptions(context, projectName, options, extensions) {
|
|
|
214
220
|
? exports.INDEX_HTML_CSR
|
|
215
221
|
: indexBaseName;
|
|
216
222
|
indexHtmlOptions = {
|
|
217
|
-
input:
|
|
223
|
+
input: indexInput,
|
|
218
224
|
output: indexOutput,
|
|
219
225
|
insertionOrder: [
|
|
220
226
|
['polyfills', true],
|
|
@@ -312,6 +318,8 @@ async function normalizeOptions(context, projectName, options, extensions) {
|
|
|
312
318
|
security,
|
|
313
319
|
templateUpdates: !!options.templateUpdates,
|
|
314
320
|
incrementalResults: !!options.incrementalResults,
|
|
321
|
+
customConditions: options.conditions,
|
|
322
|
+
frameworkVersion: await findFrameworkVersion(projectRoot),
|
|
315
323
|
};
|
|
316
324
|
}
|
|
317
325
|
async function getTailwindConfig(searchDirectories, workspaceRoot, context) {
|
|
@@ -470,3 +478,18 @@ function normalizeExternals(value) {
|
|
|
470
478
|
}
|
|
471
479
|
return [...new Set(value.map((d) => (d.endsWith('/*') ? d.slice(0, -2) : d)))];
|
|
472
480
|
}
|
|
481
|
+
async function findFrameworkVersion(projectRoot) {
|
|
482
|
+
// Create a custom require function for ESM compliance.
|
|
483
|
+
// NOTE: The trailing slash is significant.
|
|
484
|
+
const projectResolve = (0, node_module_1.createRequire)(projectRoot + '/').resolve;
|
|
485
|
+
try {
|
|
486
|
+
const manifestPath = projectResolve('@angular/core/package.json');
|
|
487
|
+
const manifestData = await (0, promises_1.readFile)(manifestPath, 'utf-8');
|
|
488
|
+
const manifestObject = JSON.parse(manifestData);
|
|
489
|
+
const version = manifestObject.version;
|
|
490
|
+
return version;
|
|
491
|
+
}
|
|
492
|
+
catch {
|
|
493
|
+
throw new Error('Error: It appears that "@angular/core" is missing as a dependency. Please ensure it is included in your project.');
|
|
494
|
+
}
|
|
495
|
+
}
|
|
@@ -37,6 +37,13 @@ export type Schema = {
|
|
|
37
37
|
* Automatically clear the terminal screen during rebuilds.
|
|
38
38
|
*/
|
|
39
39
|
clearScreen?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Custom package resolution conditions used to resolve conditional exports/imports.
|
|
42
|
+
* Defaults to ['module', 'development'/'production']. The following special conditions are
|
|
43
|
+
* always present if the requirements are satisfied: 'default', 'import', 'require',
|
|
44
|
+
* 'browser', 'node'.
|
|
45
|
+
*/
|
|
46
|
+
conditions?: string[];
|
|
40
47
|
/**
|
|
41
48
|
* Define the crossorigin attribute setting of elements that provide CORS support.
|
|
42
49
|
*/
|
|
@@ -86,7 +93,7 @@ export type Schema = {
|
|
|
86
93
|
/**
|
|
87
94
|
* Configures the generation of the application's HTML index.
|
|
88
95
|
*/
|
|
89
|
-
index
|
|
96
|
+
index?: IndexUnion;
|
|
90
97
|
/**
|
|
91
98
|
* The stylesheet language to use for the application's inline component styles.
|
|
92
99
|
*/
|
|
@@ -163,11 +170,11 @@ export type Schema = {
|
|
|
163
170
|
* The full path for the server entry point to the application, relative to the current
|
|
164
171
|
* workspace.
|
|
165
172
|
*/
|
|
166
|
-
server?:
|
|
173
|
+
server?: Serv;
|
|
167
174
|
/**
|
|
168
175
|
* Generates a service worker configuration.
|
|
169
176
|
*/
|
|
170
|
-
serviceWorker?:
|
|
177
|
+
serviceWorker?: Serv;
|
|
171
178
|
/**
|
|
172
179
|
* Output source maps for scripts and styles. For more information, see
|
|
173
180
|
* https://angular.dev/reference/configs/workspace-config#source-map-configuration.
|
|
@@ -496,9 +503,12 @@ export type AutoCspClass = {
|
|
|
496
503
|
unsafeEval?: boolean;
|
|
497
504
|
};
|
|
498
505
|
/**
|
|
506
|
+
* The full path for the server entry point to the application, relative to the current
|
|
507
|
+
* workspace.
|
|
508
|
+
*
|
|
499
509
|
* Generates a service worker configuration.
|
|
500
510
|
*/
|
|
501
|
-
export type
|
|
511
|
+
export type Serv = boolean | string;
|
|
502
512
|
/**
|
|
503
513
|
* Output source maps for scripts and styles. For more information, see
|
|
504
514
|
* https://angular.dev/reference/configs/workspace-config#source-map-configuration.
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
"description": "The full path for the browser entry point to the application, relative to the current workspace."
|
|
18
18
|
},
|
|
19
19
|
"server": {
|
|
20
|
-
"type": "string",
|
|
21
20
|
"description": "The full path for the server entry point to the application, relative to the current workspace.",
|
|
22
21
|
"oneOf": [
|
|
23
22
|
{
|
|
@@ -293,6 +292,13 @@
|
|
|
293
292
|
"type": "string"
|
|
294
293
|
}
|
|
295
294
|
},
|
|
295
|
+
"conditions": {
|
|
296
|
+
"description": "Custom package resolution conditions used to resolve conditional exports/imports. Defaults to ['module', 'development'/'production']. The following special conditions are always present if the requirements are satisfied: 'default', 'import', 'require', 'browser', 'node'.",
|
|
297
|
+
"type": "array",
|
|
298
|
+
"items": {
|
|
299
|
+
"type": "string"
|
|
300
|
+
}
|
|
301
|
+
},
|
|
296
302
|
"fileReplacements": {
|
|
297
303
|
"description": "Replace compilation source files with other compilation source files in the build.",
|
|
298
304
|
"type": "array",
|
|
@@ -610,7 +616,7 @@
|
|
|
610
616
|
}
|
|
611
617
|
},
|
|
612
618
|
"additionalProperties": false,
|
|
613
|
-
"required": ["
|
|
619
|
+
"required": ["browser", "tsConfig"],
|
|
614
620
|
"definitions": {
|
|
615
621
|
"assetPattern": {
|
|
616
622
|
"oneOf": [
|
|
@@ -121,12 +121,6 @@ async function* serveWithVite(serverOptions, builderName, builderAction, context
|
|
|
121
121
|
// This will also replace file-based/inline styles as code if external runtime styles are not enabled.
|
|
122
122
|
browserOptions.templateUpdates =
|
|
123
123
|
serverOptions.liveReload && serverOptions.hmr && environment_options_1.useComponentTemplateHmr;
|
|
124
|
-
if (browserOptions.templateUpdates) {
|
|
125
|
-
context.logger.warn('Component HMR has been enabled.\n' +
|
|
126
|
-
'If you encounter application reload issues, you can manually reload the page to bypass HMR and/or disable this feature with the' +
|
|
127
|
-
' `--no-hmr` command line option.\n' +
|
|
128
|
-
'Please consider reporting any issues you encounter here: https://github.com/angular/angular-cli/issues\n');
|
|
129
|
-
}
|
|
130
124
|
browserOptions.incrementalResults = true;
|
|
131
125
|
// Setup the prebundling transformer that will be shared across Vite prebundling requests
|
|
132
126
|
const prebundleTransformer = new internal_1.JavaScriptTransformer(
|
|
@@ -295,6 +295,7 @@ async function collectEntrypoints(options, context, projectSourceRoot) {
|
|
|
295
295
|
const testFiles = await (0, find_tests_1.findTests)(options.include ?? [], options.exclude ?? [], context.workspaceRoot, projectSourceRoot);
|
|
296
296
|
return (0, find_tests_1.getTestEntrypoints)(testFiles, { projectSourceRoot, workspaceRoot: context.workspaceRoot });
|
|
297
297
|
}
|
|
298
|
+
// eslint-disable-next-line max-lines-per-function
|
|
298
299
|
async function initializeApplication(options, context, karmaOptions, transforms = {}) {
|
|
299
300
|
const outputPath = path.join(context.workspaceRoot, 'dist/test-out', (0, node_crypto_1.randomUUID)());
|
|
300
301
|
const projectSourceRoot = await getProjectSourceRoot(context);
|
|
@@ -406,6 +407,14 @@ async function initializeApplication(options, context, karmaOptions, transforms
|
|
|
406
407
|
karmaOptions.files.push({ pattern: `*.css`, type: 'css', watched: false });
|
|
407
408
|
}
|
|
408
409
|
const parsedKarmaConfig = await karma.config.parseConfig(options.karmaConfig && path.resolve(context.workspaceRoot, options.karmaConfig), transforms.karmaOptions ? transforms.karmaOptions(karmaOptions) : karmaOptions, { promiseConfig: true, throwErrors: true });
|
|
410
|
+
// Check for jsdom which does not support executing ESM scripts.
|
|
411
|
+
// If present, remove jsdom and issue a warning.
|
|
412
|
+
const updatedBrowsers = parsedKarmaConfig.browsers?.filter((browser) => browser !== 'jsdom');
|
|
413
|
+
if (parsedKarmaConfig.browsers?.length !== updatedBrowsers?.length) {
|
|
414
|
+
parsedKarmaConfig.browsers = updatedBrowsers;
|
|
415
|
+
context.logger.warn(`'jsdom' does not support ESM code execution and cannot be used for karma testing.` +
|
|
416
|
+
` The 'jsdom' entry has been removed from the 'browsers' option.`);
|
|
417
|
+
}
|
|
409
418
|
// Remove the webpack plugin/framework:
|
|
410
419
|
// Alternative would be to make the Karma plugin "smart" but that's a tall order
|
|
411
420
|
// with managing unneeded imports etc..
|
|
@@ -76,7 +76,7 @@ function getBaseKarmaOptions(options, context) {
|
|
|
76
76
|
karmaOptions.client.clearContext ??= singleRun ?? false; // `singleRun` defaults to `false` per Karma docs.
|
|
77
77
|
// Convert browsers from a string to an array
|
|
78
78
|
if (typeof options.browsers === 'string' && options.browsers) {
|
|
79
|
-
karmaOptions.browsers = options.browsers.split(',');
|
|
79
|
+
karmaOptions.browsers = options.browsers.split(',').map((browser) => browser.trim());
|
|
80
80
|
}
|
|
81
81
|
else if (options.browsers === false) {
|
|
82
82
|
karmaOptions.browsers = [];
|
|
@@ -7,12 +7,10 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { getTestBed } from '@angular/core/testing';
|
|
10
|
-
import {
|
|
11
|
-
import { BrowserTestingModule } from '@angular/platform-browser/testing';
|
|
10
|
+
import { BrowserTestingModule, platformBrowserTesting } from '@angular/platform-browser/testing';
|
|
12
11
|
|
|
13
|
-
// TODO(alanagius): replace with `platformBrowserTesting` once https://github.com/angular/angular/pull/60480 is released.
|
|
14
12
|
// Initialize the Angular testing environment.
|
|
15
|
-
getTestBed().initTestEnvironment(BrowserTestingModule,
|
|
13
|
+
getTestBed().initTestEnvironment(BrowserTestingModule, platformBrowserTesting(), {
|
|
16
14
|
errorOnUnknownElements: true,
|
|
17
15
|
errorOnUnknownProperties: true,
|
|
18
16
|
});
|
|
@@ -382,7 +382,7 @@ function getEsBuildServerCommonOptions(options) {
|
|
|
382
382
|
};
|
|
383
383
|
}
|
|
384
384
|
function getEsBuildCommonOptions(options) {
|
|
385
|
-
const { workspaceRoot, outExtension, optimizationOptions, sourcemapOptions, tsconfig, externalDependencies, outputNames, preserveSymlinks, jit, loaderExtensions, jsonLogs, i18nOptions, } = options;
|
|
385
|
+
const { workspaceRoot, outExtension, optimizationOptions, sourcemapOptions, tsconfig, externalDependencies, outputNames, preserveSymlinks, jit, loaderExtensions, jsonLogs, i18nOptions, customConditions, frameworkVersion, } = options;
|
|
386
386
|
// Ensure unique hashes for i18n translation changes when using post-process inlining.
|
|
387
387
|
// This hash value is added as a footer to each file and ensures that the output file names (with hashes)
|
|
388
388
|
// change when translation files have changed. If this is not done the post processed files may have
|
|
@@ -393,18 +393,36 @@ function getEsBuildCommonOptions(options) {
|
|
|
393
393
|
const i18nHash = Object.values(i18nOptions.locales).reduce((data, locale) => data + locale.files.map((file) => file.integrity || '').join('|'), '');
|
|
394
394
|
footer = { js: `/**i18n:${(0, node_crypto_1.createHash)('sha256').update(i18nHash).digest('hex')}*/` };
|
|
395
395
|
}
|
|
396
|
+
// Core conditions that are always included
|
|
397
|
+
const conditions = [
|
|
398
|
+
// Required to support rxjs 7.x which will use es5 code if this condition is not present
|
|
399
|
+
'es2015',
|
|
400
|
+
'es2020',
|
|
401
|
+
];
|
|
402
|
+
// The pre-linked code is not used with JIT for two reasons:
|
|
403
|
+
// 1) The pre-linked code may not have the metadata included that is required for JIT
|
|
404
|
+
// 2) The CLI is otherwise setup to use runtime linking for JIT to match the application template compilation
|
|
405
|
+
if (!jit) {
|
|
406
|
+
// The pre-linked package condition is based on the framework version.
|
|
407
|
+
// Currently this is specific to each patch version of the framework.
|
|
408
|
+
conditions.push('angular:linked-' + frameworkVersion);
|
|
409
|
+
}
|
|
410
|
+
// Append custom conditions if present
|
|
411
|
+
if (customConditions) {
|
|
412
|
+
conditions.push(...customConditions);
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
// Include default conditions
|
|
416
|
+
conditions.push('module');
|
|
417
|
+
conditions.push(optimizationOptions.scripts ? 'production' : 'development');
|
|
418
|
+
}
|
|
396
419
|
return {
|
|
397
420
|
absWorkingDir: workspaceRoot,
|
|
398
421
|
format: 'esm',
|
|
399
422
|
bundle: true,
|
|
400
423
|
packages: 'bundle',
|
|
401
424
|
assetNames: outputNames.media,
|
|
402
|
-
conditions
|
|
403
|
-
'es2020',
|
|
404
|
-
'es2015',
|
|
405
|
-
'module',
|
|
406
|
-
optimizationOptions.scripts ? 'production' : 'development',
|
|
407
|
-
],
|
|
425
|
+
conditions,
|
|
408
426
|
resolveExtensions: ['.ts', '.tsx', '.mjs', '.js', '.cjs'],
|
|
409
427
|
metafile: true,
|
|
410
428
|
legalComments: options.extractLicenses ? 'none' : 'eof',
|
|
@@ -70,9 +70,7 @@ async function transformWithBabel(filename, data, options) {
|
|
|
70
70
|
const shouldLink = !options.skipLinker && (await requiresLinking(filename, data));
|
|
71
71
|
const useInputSourcemap = options.sourcemap &&
|
|
72
72
|
(!!options.thirdPartySourcemaps || !/[\\/]node_modules[\\/]/.test(filename));
|
|
73
|
-
|
|
74
|
-
const { default: importAttributePlugin } = await Promise.resolve().then(() => __importStar(require('@babel/plugin-syntax-import-attributes')));
|
|
75
|
-
const plugins = [importAttributePlugin];
|
|
73
|
+
const plugins = [];
|
|
76
74
|
if (options.instrumentForCoverage) {
|
|
77
75
|
const { default: coveragePlugin } = await Promise.resolve().then(() => __importStar(require('../babel/plugins/add-code-coverage.js')));
|
|
78
76
|
plugins.push(coveragePlugin);
|
|
@@ -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.0.0-next.
|
|
13
|
+
const VERSION = '20.0.0-next.4';
|
|
14
14
|
function hasCacheMetadata(value) {
|
|
15
15
|
return (!!value &&
|
|
16
16
|
typeof value === 'object' &&
|