@angular/build 19.1.4 → 19.1.5
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/README.md +1 -1
- package/package.json +6 -5
- package/src/builders/application/build-action.js +29 -2
- package/src/builders/dev-server/options.d.ts +1 -0
- package/src/builders/dev-server/options.js +2 -1
- package/src/builders/dev-server/schema.d.ts +12 -0
- package/src/builders/dev-server/schema.json +17 -0
- package/src/builders/dev-server/vite-server.js +26 -12
- package/src/tools/angular/compilation/angular-compilation.js +3 -0
- package/src/tools/vite/middlewares/ssr-middleware.js +4 -0
- package/src/utils/normalize-cache.js +1 -1
- package/src/utils/service-worker.d.ts +1 -1
- package/src/utils/service-worker.js +3 -7
package/README.md
CHANGED
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
|
|
3
3
|
The sources for this package are in the [Angular CLI](https://github.com/angular/angular-cli) repository. Please file issues and pull requests against that repository.
|
|
4
4
|
|
|
5
|
-
Usage information and reference details can be found in repository [README](
|
|
5
|
+
Usage information and reference details can be found in repository [README](https://github.com/angular/angular-cli/blob/main/README.md) file.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@angular/build",
|
|
3
|
-
"version": "19.1.
|
|
3
|
+
"version": "19.1.5",
|
|
4
4
|
"description": "Official build system for Angular",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Angular CLI",
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
"builders": "builders.json",
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@ampproject/remapping": "2.3.0",
|
|
26
|
-
"@angular-devkit/
|
|
26
|
+
"@angular-devkit/core": "19.1.5",
|
|
27
|
+
"@angular-devkit/architect": "0.1901.5",
|
|
27
28
|
"@babel/core": "7.26.0",
|
|
28
29
|
"@babel/helper-annotate-as-pure": "7.25.9",
|
|
29
30
|
"@babel/helper-split-export-declaration": "7.24.7",
|
|
@@ -45,7 +46,7 @@
|
|
|
45
46
|
"rollup": "4.30.1",
|
|
46
47
|
"sass": "1.83.1",
|
|
47
48
|
"semver": "7.6.3",
|
|
48
|
-
"vite": "6.0.
|
|
49
|
+
"vite": "6.0.11",
|
|
49
50
|
"watchpack": "2.4.2"
|
|
50
51
|
},
|
|
51
52
|
"optionalDependencies": {
|
|
@@ -57,11 +58,11 @@
|
|
|
57
58
|
"@angular/localize": "^19.0.0",
|
|
58
59
|
"@angular/platform-server": "^19.0.0",
|
|
59
60
|
"@angular/service-worker": "^19.0.0",
|
|
60
|
-
"@angular/ssr": "^19.1.
|
|
61
|
+
"@angular/ssr": "^19.1.5",
|
|
61
62
|
"less": "^4.2.0",
|
|
62
63
|
"ng-packagr": "^19.0.0",
|
|
63
64
|
"postcss": "^8.4.0",
|
|
64
|
-
"tailwindcss": "^2.0.0 || ^3.0.0",
|
|
65
|
+
"tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0",
|
|
65
66
|
"typescript": ">=5.5 <5.8"
|
|
66
67
|
},
|
|
67
68
|
"peerDependenciesMeta": {
|
|
@@ -239,6 +239,7 @@ function* emitOutputResults({ outputFiles, assetFiles, errors, warnings, externa
|
|
|
239
239
|
outputOptions,
|
|
240
240
|
},
|
|
241
241
|
};
|
|
242
|
+
let hasCssUpdates = false;
|
|
242
243
|
// Initially assume all previous output files have been removed
|
|
243
244
|
const removedOutputFiles = new Map(previousOutputInfo);
|
|
244
245
|
for (const file of outputFiles) {
|
|
@@ -254,8 +255,11 @@ function* emitOutputResults({ outputFiles, assetFiles, errors, warnings, externa
|
|
|
254
255
|
incrementalResult.modified.push(file.path);
|
|
255
256
|
}
|
|
256
257
|
if (needFile) {
|
|
257
|
-
|
|
258
|
-
|
|
258
|
+
if (file.path.endsWith('.css')) {
|
|
259
|
+
hasCssUpdates = true;
|
|
260
|
+
}
|
|
261
|
+
else if (!/(?:\.m?js|\.map)$/.test(file.path)) {
|
|
262
|
+
// Updates to non-JS files must signal an update with the dev server
|
|
259
263
|
incrementalResult.background = false;
|
|
260
264
|
}
|
|
261
265
|
incrementalResult.files[file.path] = {
|
|
@@ -281,12 +285,21 @@ function* emitOutputResults({ outputFiles, assetFiles, errors, warnings, externa
|
|
|
281
285
|
else {
|
|
282
286
|
continue;
|
|
283
287
|
}
|
|
288
|
+
hasCssUpdates ||= destination.endsWith('.css');
|
|
284
289
|
incrementalResult.files[destination] = {
|
|
285
290
|
type: bundler_context_1.BuildOutputFileType.Browser,
|
|
286
291
|
inputPath: source,
|
|
287
292
|
origin: 'disk',
|
|
288
293
|
};
|
|
289
294
|
}
|
|
295
|
+
// Do not remove stale files yet if there are template updates.
|
|
296
|
+
// Component chunk files may still be referenced in running browser code.
|
|
297
|
+
// Module evaluation time component updates will update any of these files.
|
|
298
|
+
// This typically occurs when a lazy component is changed that has not yet
|
|
299
|
+
// been accessed at runtime.
|
|
300
|
+
if (hasTemplateUpdates && incrementalResult.background) {
|
|
301
|
+
removedOutputFiles.clear();
|
|
302
|
+
}
|
|
290
303
|
// Include the removed output and asset files
|
|
291
304
|
incrementalResult.removed.push(...Array.from(removedOutputFiles, ([file, { type }]) => ({
|
|
292
305
|
path: file,
|
|
@@ -299,6 +312,17 @@ function* emitOutputResults({ outputFiles, assetFiles, errors, warnings, externa
|
|
|
299
312
|
// If there are template updates and the incremental update was background only, a component
|
|
300
313
|
// update is possible.
|
|
301
314
|
if (hasTemplateUpdates && incrementalResult.background) {
|
|
315
|
+
// Template changes may be accompanied by stylesheet changes and these should also be updated hot when possible.
|
|
316
|
+
if (hasCssUpdates) {
|
|
317
|
+
const styleResult = {
|
|
318
|
+
kind: results_1.ResultKind.Incremental,
|
|
319
|
+
added: incrementalResult.added.filter(isCssFilePath),
|
|
320
|
+
removed: incrementalResult.removed.filter(({ path }) => isCssFilePath(path)),
|
|
321
|
+
modified: incrementalResult.modified.filter(isCssFilePath),
|
|
322
|
+
files: Object.fromEntries(Object.entries(incrementalResult.files).filter(([path]) => isCssFilePath(path))),
|
|
323
|
+
};
|
|
324
|
+
yield styleResult;
|
|
325
|
+
}
|
|
302
326
|
const updateResult = {
|
|
303
327
|
kind: results_1.ResultKind.ComponentUpdate,
|
|
304
328
|
updates: Array.from(templateUpdates, ([id, content]) => ({
|
|
@@ -310,3 +334,6 @@ function* emitOutputResults({ outputFiles, assetFiles, errors, warnings, externa
|
|
|
310
334
|
yield updateResult;
|
|
311
335
|
}
|
|
312
336
|
}
|
|
337
|
+
function isCssFilePath(filePath) {
|
|
338
|
+
return /\.css(?:\.map)?$/i.test(filePath);
|
|
339
|
+
}
|
|
@@ -73,7 +73,7 @@ async function normalizeOptions(context, projectName, options) {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
// Initial options to keep
|
|
76
|
-
const { host, port, poll, open, verbose, watch, liveReload, hmr, headers, proxyConfig, servePath, ssl, sslCert, sslKey, prebundle, } = options;
|
|
76
|
+
const { host, port, poll, open, verbose, watch, liveReload, hmr, headers, proxyConfig, servePath, ssl, sslCert, sslKey, prebundle, allowedHosts, } = options;
|
|
77
77
|
// Return all the normalized options
|
|
78
78
|
return {
|
|
79
79
|
buildTarget,
|
|
@@ -97,5 +97,6 @@ async function normalizeOptions(context, projectName, options) {
|
|
|
97
97
|
// Prebundling defaults to true but requires caching to function
|
|
98
98
|
prebundle: cacheOptions.enabled && !optimization.scripts && prebundle,
|
|
99
99
|
inspect,
|
|
100
|
+
allowedHosts: allowedHosts ? allowedHosts : [],
|
|
100
101
|
};
|
|
101
102
|
}
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
* Dev Server target options for Build Facade.
|
|
3
3
|
*/
|
|
4
4
|
export type Schema = {
|
|
5
|
+
/**
|
|
6
|
+
* The hosts that can access the development server. This option sets the Vite option of the
|
|
7
|
+
* same name. For further details:
|
|
8
|
+
* https://vite.dev/config/server-options.html#server-allowedhosts
|
|
9
|
+
*/
|
|
10
|
+
allowedHosts?: AllowedHosts;
|
|
5
11
|
/**
|
|
6
12
|
* A build builder target to serve in the format of `project:target[:configuration]`. You
|
|
7
13
|
* can also pass in more than one configuration name as a comma-separated list. Example:
|
|
@@ -79,6 +85,12 @@ export type Schema = {
|
|
|
79
85
|
*/
|
|
80
86
|
watch?: boolean;
|
|
81
87
|
};
|
|
88
|
+
/**
|
|
89
|
+
* The hosts that can access the development server. This option sets the Vite option of the
|
|
90
|
+
* same name. For further details:
|
|
91
|
+
* https://vite.dev/config/server-options.html#server-allowedhosts
|
|
92
|
+
*/
|
|
93
|
+
export type AllowedHosts = string[] | boolean;
|
|
82
94
|
/**
|
|
83
95
|
* Activate debugging inspector. This option only has an effect when 'SSR' or 'SSG' are
|
|
84
96
|
* enabled.
|
|
@@ -36,6 +36,23 @@
|
|
|
36
36
|
"type": "string",
|
|
37
37
|
"description": "SSL certificate to use for serving HTTPS."
|
|
38
38
|
},
|
|
39
|
+
"allowedHosts": {
|
|
40
|
+
"description": "The hosts that can access the development server. This option sets the Vite option of the same name. For further details: https://vite.dev/config/server-options.html#server-allowedhosts",
|
|
41
|
+
"default": [],
|
|
42
|
+
"oneOf": [
|
|
43
|
+
{
|
|
44
|
+
"type": "array",
|
|
45
|
+
"description": "List of hosts that are allowed to access the development server.",
|
|
46
|
+
"items": {
|
|
47
|
+
"type": "string"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"type": "boolean",
|
|
52
|
+
"description": "Indicates that all hosts are allowed. This is not recommended and a security risk."
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
},
|
|
39
56
|
"headers": {
|
|
40
57
|
"type": "object",
|
|
41
58
|
"description": "Custom HTTP headers to be added to all responses.",
|
|
@@ -304,6 +304,23 @@ async function* serveWithVite(serverOptions, builderName, builderAction, context
|
|
|
304
304
|
const serverConfiguration = await setupServer(serverOptions, generatedFiles, assetFiles, browserOptions.preserveSymlinks, externalMetadata, ssrMode, prebundleTransformer, target, (0, internal_1.isZonelessApp)(polyfills), componentStyles, templateUpdates, browserOptions.loader, browserOptions.define, extensions?.middleware, transformers?.indexHtml, thirdPartySourcemaps);
|
|
305
305
|
server = await createServer(serverConfiguration);
|
|
306
306
|
await server.listen();
|
|
307
|
+
// Setup builder context logging for browser clients
|
|
308
|
+
server.hot.on('angular:log', (data) => {
|
|
309
|
+
if (typeof data?.text !== 'string') {
|
|
310
|
+
context.logger.warn('Development server client sent invalid internal log event.');
|
|
311
|
+
}
|
|
312
|
+
switch (data.kind) {
|
|
313
|
+
case 'error':
|
|
314
|
+
context.logger.error(`[CLIENT ERROR]: ${data.text}`);
|
|
315
|
+
break;
|
|
316
|
+
case 'warning':
|
|
317
|
+
context.logger.warn(`[CLIENT WARNING]: ${data.text}`);
|
|
318
|
+
break;
|
|
319
|
+
default:
|
|
320
|
+
context.logger.info(`[CLIENT INFO]: ${data.text}`);
|
|
321
|
+
break;
|
|
322
|
+
}
|
|
323
|
+
});
|
|
307
324
|
const urls = server.resolvedUrls;
|
|
308
325
|
if (urls && (urls.local.length || urls.network.length)) {
|
|
309
326
|
serverUrl = new URL(urls.local[0] ?? urls.network[0]);
|
|
@@ -353,26 +370,22 @@ async function invalidateUpdatedFiles(normalizePath, generatedFiles, assetFiles,
|
|
|
353
370
|
updatedFiles.push(file);
|
|
354
371
|
}
|
|
355
372
|
// Invalidate any updated files
|
|
356
|
-
let
|
|
373
|
+
let serverApplicationChanged = false;
|
|
357
374
|
for (const [file, record] of generatedFiles) {
|
|
358
375
|
if (!record.updated) {
|
|
359
376
|
continue;
|
|
360
377
|
}
|
|
361
378
|
record.updated = false;
|
|
362
|
-
if (record.type === internal_1.BuildOutputFileType.ServerApplication && !destroyAngularServerAppCalled) {
|
|
363
|
-
// Clear the server app cache
|
|
364
|
-
// This must be done before module invalidation.
|
|
365
|
-
const { ɵdestroyAngularServerApp } = (await server.ssrLoadModule('/main.server.mjs'));
|
|
366
|
-
ɵdestroyAngularServerApp();
|
|
367
|
-
destroyAngularServerAppCalled = true;
|
|
368
|
-
}
|
|
369
379
|
updatedFiles.push(file);
|
|
380
|
+
serverApplicationChanged ||= record.type === internal_1.BuildOutputFileType.ServerApplication;
|
|
370
381
|
const updatedModules = server.moduleGraph.getModulesByFile(normalizePath((0, node_path_1.join)(server.config.root, file)));
|
|
371
382
|
updatedModules?.forEach((m) => server.moduleGraph.invalidateModule(m));
|
|
372
383
|
}
|
|
373
|
-
if (
|
|
374
|
-
//
|
|
375
|
-
|
|
384
|
+
if (serverApplicationChanged) {
|
|
385
|
+
// Clear the server app cache and
|
|
386
|
+
// trigger module evaluation before reload to initiate dependency optimization.
|
|
387
|
+
const { ɵdestroyAngularServerApp } = (await server.ssrLoadModule('/main.server.mjs'));
|
|
388
|
+
ɵdestroyAngularServerApp();
|
|
376
389
|
}
|
|
377
390
|
return updatedFiles;
|
|
378
391
|
}
|
|
@@ -424,7 +437,7 @@ function handleUpdate(server, serverOptions, logger, componentStyles, updatedFil
|
|
|
424
437
|
type: 'update',
|
|
425
438
|
updates,
|
|
426
439
|
});
|
|
427
|
-
logger.info('
|
|
440
|
+
logger.info('Stylesheet update sent to client(s).');
|
|
428
441
|
return;
|
|
429
442
|
}
|
|
430
443
|
}
|
|
@@ -545,6 +558,7 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
|
|
|
545
558
|
strictPort: true,
|
|
546
559
|
host: serverOptions.host,
|
|
547
560
|
open: serverOptions.open,
|
|
561
|
+
allowedHosts: serverOptions.allowedHosts,
|
|
548
562
|
headers: serverOptions.headers,
|
|
549
563
|
// Disable the websocket if live reload is disabled (false/undefined are the only valid values)
|
|
550
564
|
ws: serverOptions.liveReload === false && serverOptions.hmr === false ? false : undefined,
|
|
@@ -80,6 +80,9 @@ class AngularCompilation {
|
|
|
80
80
|
enableResourceInlining: false,
|
|
81
81
|
supportTestBed: false,
|
|
82
82
|
supportJitMode: false,
|
|
83
|
+
// Disable removing of comments as TS is quite aggressive with these and can
|
|
84
|
+
// remove important annotations, such as /* @__PURE__ */ and comments like /* vite-ignore */.
|
|
85
|
+
removeComments: false,
|
|
83
86
|
}));
|
|
84
87
|
}
|
|
85
88
|
async diagnoseFiles(modes = DiagnosticModes.All) {
|
|
@@ -22,6 +22,10 @@ function createAngularSsrInternalMiddleware(server, indexHtmlTransformer) {
|
|
|
22
22
|
// which must be processed by the runtime linker, even if they are not used.
|
|
23
23
|
await (0, load_esm_1.loadEsmModule)('@angular/compiler');
|
|
24
24
|
const { writeResponseToNodeResponse, createWebRequestFromNodeRequest } = await (0, load_esm_1.loadEsmModule)('@angular/ssr/node');
|
|
25
|
+
// The following is necessary because accessing the module after invalidation may result in an empty module,
|
|
26
|
+
// which can trigger a `TypeError: ɵgetOrCreateAngularServerApp is not a function` error.
|
|
27
|
+
// TODO: look into why.
|
|
28
|
+
await server.ssrLoadModule('/main.server.mjs');
|
|
25
29
|
const { ɵgetOrCreateAngularServerApp } = (await server.ssrLoadModule('/main.server.mjs'));
|
|
26
30
|
const angularServerApp = ɵgetOrCreateAngularServerApp({
|
|
27
31
|
allowStaticRouteRender: true,
|
|
@@ -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 = '19.1.
|
|
13
|
+
const VERSION = '19.1.5';
|
|
14
14
|
function hasCacheMetadata(value) {
|
|
15
15
|
return (!!value &&
|
|
16
16
|
typeof value === 'object' &&
|
|
@@ -9,7 +9,7 @@ import type { Config, Filesystem } from '@angular/service-worker/config';
|
|
|
9
9
|
import { promises as fsPromises } from 'node:fs';
|
|
10
10
|
import { BuildOutputFile } from '../tools/esbuild/bundler-context';
|
|
11
11
|
import { BuildOutputAsset } from '../tools/esbuild/bundler-execution-result';
|
|
12
|
-
export declare function augmentAppWithServiceWorker(appRoot: string, workspaceRoot: string, outputPath: string, baseHref: string, ngswConfigPath?: string,
|
|
12
|
+
export declare function augmentAppWithServiceWorker(appRoot: string, workspaceRoot: string, outputPath: string, baseHref: string, ngswConfigPath?: string, inputFileSystem?: typeof fsPromises, outputFileSystem?: typeof fsPromises): Promise<void>;
|
|
13
13
|
export declare function augmentAppWithServiceWorkerEsbuild(workspaceRoot: string, configPath: string, baseHref: string, indexHtml: string | undefined, outputFiles: BuildOutputFile[], assetFiles: BuildOutputAsset[]): Promise<{
|
|
14
14
|
manifest: string;
|
|
15
15
|
assetFiles: BuildOutputAsset[];
|
|
@@ -133,7 +133,7 @@ class ResultFilesystem {
|
|
|
133
133
|
throw new Error('Serviceworker manifest generator should not attempted to write.');
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
|
-
async function augmentAppWithServiceWorker(appRoot, workspaceRoot, outputPath, baseHref, ngswConfigPath,
|
|
136
|
+
async function augmentAppWithServiceWorker(appRoot, workspaceRoot, outputPath, baseHref, ngswConfigPath, inputFileSystem = node_fs_1.promises, outputFileSystem = node_fs_1.promises) {
|
|
137
137
|
// Determine the configuration file path
|
|
138
138
|
const configPath = ngswConfigPath
|
|
139
139
|
? path.join(workspaceRoot, ngswConfigPath)
|
|
@@ -141,7 +141,7 @@ async function augmentAppWithServiceWorker(appRoot, workspaceRoot, outputPath, b
|
|
|
141
141
|
// Read the configuration file
|
|
142
142
|
let config;
|
|
143
143
|
try {
|
|
144
|
-
const configurationData = await
|
|
144
|
+
const configurationData = await inputFileSystem.readFile(configPath, 'utf-8');
|
|
145
145
|
config = JSON.parse(configurationData);
|
|
146
146
|
}
|
|
147
147
|
catch (error) {
|
|
@@ -158,11 +158,7 @@ async function augmentAppWithServiceWorker(appRoot, workspaceRoot, outputPath, b
|
|
|
158
158
|
const result = await augmentAppWithServiceWorkerCore(config, new CliFilesystem(outputFileSystem, outputPath), baseHref);
|
|
159
159
|
const copy = async (src, dest) => {
|
|
160
160
|
const resolvedDest = path.join(outputPath, dest);
|
|
161
|
-
return
|
|
162
|
-
? // Native FS (Builder).
|
|
163
|
-
inputputFileSystem.copyFile(src, resolvedDest, node_fs_1.constants.COPYFILE_FICLONE)
|
|
164
|
-
: // memfs (Webpack): Read the file from the input FS (disk) and write it to the output FS (memory).
|
|
165
|
-
outputFileSystem.writeFile(resolvedDest, await inputputFileSystem.readFile(src));
|
|
161
|
+
return outputFileSystem.writeFile(resolvedDest, await inputFileSystem.readFile(src));
|
|
166
162
|
};
|
|
167
163
|
await outputFileSystem.writeFile(path.join(outputPath, 'ngsw.json'), result.manifest);
|
|
168
164
|
for (const { source, destination } of result.assetFiles) {
|