@angular-devkit/build-angular 17.3.0 → 17.3.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 CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@angular-devkit/build-angular",
3
- "version": "17.3.0",
3
+ "version": "17.3.2",
4
4
  "description": "Angular Webpack Build Facade",
5
5
  "main": "src/index.js",
6
6
  "typings": "src/index.d.ts",
7
7
  "builders": "builders.json",
8
8
  "dependencies": {
9
9
  "@ampproject/remapping": "2.3.0",
10
- "@angular-devkit/architect": "0.1703.0",
11
- "@angular-devkit/build-webpack": "0.1703.0",
12
- "@angular-devkit/core": "17.3.0",
10
+ "@angular-devkit/architect": "0.1703.2",
11
+ "@angular-devkit/build-webpack": "0.1703.2",
12
+ "@angular-devkit/core": "17.3.2",
13
13
  "@babel/core": "7.24.0",
14
14
  "@babel/generator": "7.23.6",
15
15
  "@babel/helper-annotate-as-pure": "7.22.5",
@@ -20,7 +20,7 @@
20
20
  "@babel/preset-env": "7.24.0",
21
21
  "@babel/runtime": "7.24.0",
22
22
  "@discoveryjs/json-ext": "0.5.7",
23
- "@ngtools/webpack": "17.3.0",
23
+ "@ngtools/webpack": "17.3.2",
24
24
  "@vitejs/plugin-basic-ssl": "1.1.0",
25
25
  "ansi-colors": "4.1.3",
26
26
  "autoprefixer": "10.4.18",
@@ -65,7 +65,7 @@
65
65
  "vite": "5.1.5",
66
66
  "watchpack": "2.4.0",
67
67
  "webpack": "5.90.3",
68
- "webpack-dev-middleware": "6.1.1",
68
+ "webpack-dev-middleware": "6.1.2",
69
69
  "webpack-dev-server": "4.15.1",
70
70
  "webpack-merge": "5.10.0",
71
71
  "webpack-subresource-integrity": "5.1.0"
@@ -11,6 +11,7 @@ import { BuildOutputFile } from '../../tools/esbuild/bundler-context';
11
11
  import { ExecutionResult, RebuildState } from '../../tools/esbuild/bundler-execution-result';
12
12
  import { NormalizedCachedOptions } from '../../utils/normalize-cache';
13
13
  import { NormalizedOutputOptions } from './options';
14
+ type BuildActionOutput = (ExecutionResult['outputWithFiles'] | ExecutionResult['output']) & BuilderOutput;
14
15
  export declare function runEsBuildBuildAction(action: (rebuildState?: RebuildState) => Promise<ExecutionResult>, options: {
15
16
  workspaceRoot: string;
16
17
  projectRoot: string;
@@ -29,4 +30,5 @@ export declare function runEsBuildBuildAction(action: (rebuildState?: RebuildSta
29
30
  clearScreen?: boolean;
30
31
  colors?: boolean;
31
32
  jsonLogs?: boolean;
32
- }): AsyncIterable<(ExecutionResult['outputWithFiles'] | ExecutionResult['output']) & BuilderOutput>;
33
+ }): AsyncIterable<BuildActionOutput>;
34
+ export {};
@@ -117,16 +117,7 @@ async function* runEsBuildBuildAction(action, options) {
117
117
  // Output the first build results after setting up the watcher to ensure that any code executed
118
118
  // higher in the iterator call stack will trigger the watcher. This is particularly relevant for
119
119
  // unit tests which execute the builder and modify the file system programmatically.
120
- if (writeToFileSystem) {
121
- // Write output files
122
- await (0, utils_1.writeResultFiles)(result.outputFiles, result.assetFiles, outputOptions);
123
- yield result.output;
124
- }
125
- else {
126
- // Requires casting due to unneeded `JsonObject` requirement. Remove once fixed.
127
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
128
- yield result.outputWithFiles;
129
- }
120
+ yield await writeAndEmitOutput(writeToFileSystem, result, outputOptions, writeToFileSystemFilter);
130
121
  // Finish if watch mode is not enabled
131
122
  if (!watcher) {
132
123
  return;
@@ -165,19 +156,7 @@ async function* runEsBuildBuildAction(action, options) {
165
156
  if (staleWatchFiles?.size) {
166
157
  watcher.remove([...staleWatchFiles]);
167
158
  }
168
- if (writeToFileSystem) {
169
- // Write output files
170
- const filesToWrite = writeToFileSystemFilter
171
- ? result.outputFiles.filter(writeToFileSystemFilter)
172
- : result.outputFiles;
173
- await (0, utils_1.writeResultFiles)(filesToWrite, result.assetFiles, outputOptions);
174
- yield result.output;
175
- }
176
- else {
177
- // Requires casting due to unneeded `JsonObject` requirement. Remove once fixed.
178
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
179
- yield result.outputWithFiles;
180
- }
159
+ yield await writeAndEmitOutput(writeToFileSystem, result, outputOptions, writeToFileSystemFilter);
181
160
  }
182
161
  }
183
162
  finally {
@@ -187,3 +166,18 @@ async function* runEsBuildBuildAction(action, options) {
187
166
  }
188
167
  }
189
168
  exports.runEsBuildBuildAction = runEsBuildBuildAction;
169
+ async function writeAndEmitOutput(writeToFileSystem, { outputFiles, output, outputWithFiles, assetFiles }, outputOptions, writeToFileSystemFilter) {
170
+ if (writeToFileSystem) {
171
+ // Write output files
172
+ const outputFilesToWrite = writeToFileSystemFilter
173
+ ? outputFiles.filter(writeToFileSystemFilter)
174
+ : outputFiles;
175
+ await (0, utils_1.writeResultFiles)(outputFilesToWrite, assetFiles, outputOptions);
176
+ return output;
177
+ }
178
+ else {
179
+ // Requires casting due to unneeded `JsonObject` requirement. Remove once fixed.
180
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
181
+ return outputWithFiles;
182
+ }
183
+ }
@@ -75,7 +75,7 @@ async function executePostBundleSteps(options, outputFiles, assetFiles, initialF
75
75
  // If localization is enabled, service worker is handled in the inlining process.
76
76
  if (serviceWorker) {
77
77
  try {
78
- const serviceWorkerResult = await (0, service_worker_1.augmentAppWithServiceWorkerEsbuild)(workspaceRoot, serviceWorker, options.baseHref || '/',
78
+ const serviceWorkerResult = await (0, service_worker_1.augmentAppWithServiceWorkerEsbuild)(workspaceRoot, serviceWorker, options.baseHref || '/', options.indexHtmlOptions?.output,
79
79
  // Ensure additional files recently added are used
80
80
  [...outputFiles, ...additionalOutputFiles], assetFiles);
81
81
  additionalOutputFiles.push((0, utils_1.createOutputFileFromText)('ngsw.json', serviceWorkerResult.manifest, bundler_context_1.BuildOutputFileType.Browser));
@@ -211,7 +211,9 @@ async function normalizeOptions(context, projectName, options, extensions) {
211
211
  fileReplacements,
212
212
  globalStyles,
213
213
  globalScripts,
214
- serviceWorker: typeof serviceWorker === 'string' ? node_path_1.default.join(workspaceRoot, serviceWorker) : undefined,
214
+ serviceWorker: serviceWorker
215
+ ? node_path_1.default.join(workspaceRoot, typeof serviceWorker === 'string' ? serviceWorker : 'src/ngsw-config.json')
216
+ : undefined,
215
217
  indexHtmlOptions,
216
218
  tailwindConfiguration,
217
219
  postcssConfiguration,
@@ -68,7 +68,7 @@ function execute(options, context, transforms = {}, extensions) {
68
68
  context.logger.warn(`Prebundling has been configured but will not be used because caching has been disabled.`);
69
69
  }
70
70
  if (options.allowedHosts?.length) {
71
- context.logger.warn(`The "allowedHost" option will not be used because it is not supported by the "${builderName}" builder.`);
71
+ context.logger.warn(`The "allowedHosts" option will not be used because it is not supported by the "${builderName}" builder.`);
72
72
  }
73
73
  if (options.publicHost) {
74
74
  context.logger.warn(`The "publicHost" option will not be used because it is not supported by the "${builderName}" builder.`);
@@ -156,7 +156,7 @@ exports.log = log;
156
156
  function startNodeServer(serverOutput, port, logger, inspectMode = false) {
157
157
  const outputPath = serverOutput.outputPath;
158
158
  const path = (0, path_1.join)(outputPath, 'main.js');
159
- const env = { ...process.env, PORT: '' + port };
159
+ const env = { ...process.env, SSR_PORT: '' + port, PORT: '' + port };
160
160
  const args = ['--enable-source-maps', `"${path}"`];
161
161
  if (inspectMode) {
162
162
  args.unshift('--inspect-brk');
@@ -45,6 +45,10 @@ function createAngularCompilerHost(compilerOptions, hostOptions) {
45
45
  if (context.type !== 'style') {
46
46
  return null;
47
47
  }
48
+ // No transformation required if the resource is empty
49
+ if (data.trim().length === 0) {
50
+ return { content: '' };
51
+ }
48
52
  const result = await hostOptions.transformStylesheet(data, context.containingFile, context.resourceFile ?? undefined);
49
53
  return typeof result === 'string' ? { content: result } : null;
50
54
  };
@@ -307,8 +307,11 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
307
307
  }
308
308
  // Combine additional metafiles with main metafile
309
309
  if (result.metafile && metafile) {
310
- result.metafile.inputs = { ...result.metafile.inputs, ...metafile.inputs };
311
- result.metafile.outputs = { ...result.metafile.outputs, ...metafile.outputs };
310
+ // Append the existing object, by appending to it we prevent unnecessary new objections creations with spread
311
+ // mitigating significant performance overhead for large apps.
312
+ // See: https://bugs.chromium.org/p/v8/issues/detail?id=11536
313
+ Object.assign(result.metafile.inputs, metafile.inputs);
314
+ Object.assign(result.metafile.outputs, metafile.outputs);
312
315
  }
313
316
  }
314
317
  (0, profiling_1.logCumulativeDurations)();
@@ -85,8 +85,8 @@ class BundlerContext {
85
85
  }
86
86
  // Combine metafiles used for the stats option as well as bundle budgets and console output
87
87
  if (result.metafile) {
88
- metafile.inputs = { ...metafile.inputs, ...result.metafile.inputs };
89
- metafile.outputs = { ...metafile.outputs, ...result.metafile.outputs };
88
+ Object.assign(metafile.inputs, result.metafile.inputs);
89
+ Object.assign(metafile.outputs, result.metafile.outputs);
90
90
  }
91
91
  result.initialFiles.forEach((value, key) => initialFiles.set(key, value));
92
92
  outputFiles.push(...result.outputFiles);
@@ -22,7 +22,7 @@ export declare function withNoProgress<T>(text: string, action: () => T | Promis
22
22
  * @returns An object that can be used with the esbuild build `supported` option.
23
23
  */
24
24
  export declare function getFeatureSupport(target: string[]): BuildOptions['supported'];
25
- export declare function writeResultFiles(outputFiles: BuildOutputFile[], assetFiles: BuildOutputAsset[] | undefined, { base, browser, media, server }: NormalizedOutputOptions): Promise<void>;
25
+ export declare function writeResultFiles(outputFiles: BuildOutputFile[], assetFiles: BuildOutputAsset[] | undefined, { base, browser, server }: NormalizedOutputOptions): Promise<void>;
26
26
  export declare function emitFilesToDisk<T = BuildOutputAsset | BuildOutputFile>(files: T[], writeFileCallback: (file: T) => Promise<void>): Promise<void>;
27
27
  export declare function createOutputFileFromText(path: string, text: string, type: BuildOutputFileType): BuildOutputFile;
28
28
  export declare function createOutputFileFromData(path: string, data: Uint8Array, type: BuildOutputFileType): BuildOutputFile;
@@ -179,7 +179,7 @@ function getFeatureSupport(target) {
179
179
  return supported;
180
180
  }
181
181
  exports.getFeatureSupport = getFeatureSupport;
182
- async function writeResultFiles(outputFiles, assetFiles, { base, browser, media, server }) {
182
+ async function writeResultFiles(outputFiles, assetFiles, { base, browser, server }) {
183
183
  const directoryExists = new Set();
184
184
  const ensureDirectoryExists = async (destPath) => {
185
185
  const basePath = (0, node_path_1.dirname)(destPath);
@@ -205,15 +205,25 @@ class RelativeUrlRebasingImporter extends UrlRebasingImporter {
205
205
  foundImports = [];
206
206
  cachedEntries = { files: new Set(), directories: new Set() };
207
207
  for (const entry of entries) {
208
- const isDirectory = entry.isDirectory();
208
+ let isDirectory;
209
+ let isFile;
210
+ if (entry.isSymbolicLink()) {
211
+ const stats = (0, node_fs_1.statSync)((0, node_path_1.join)(entry.path, entry.name));
212
+ isDirectory = stats.isDirectory();
213
+ isFile = stats.isFile();
214
+ }
215
+ else {
216
+ isDirectory = entry.isDirectory();
217
+ isFile = entry.isFile();
218
+ }
209
219
  if (isDirectory) {
210
220
  cachedEntries.directories.add(entry.name);
221
+ // Record if the name should be checked as a directory with an index file
222
+ if (checkDirectory && !hasStyleExtension && entry.name === filename) {
223
+ hasPotentialIndex = true;
224
+ }
211
225
  }
212
- // Record if the name should be checked as a directory with an index file
213
- if (checkDirectory && !hasStyleExtension && entry.name === filename && isDirectory) {
214
- hasPotentialIndex = true;
215
- }
216
- if (!entry.isFile()) {
226
+ if (!isFile) {
217
227
  continue;
218
228
  }
219
229
  cachedEntries.files.add(entry.name);
@@ -159,9 +159,11 @@ function createAngularMemoryPlugin(options) {
159
159
  return;
160
160
  }
161
161
  transformIndexHtmlAndAddHeaders(req.url, rawHtml, res, next, async (html) => {
162
+ const resolvedUrls = server.resolvedUrls;
163
+ const baseUrl = resolvedUrls?.local[0] ?? resolvedUrls?.network[0];
162
164
  const { content } = await (0, render_page_1.renderPage)({
163
165
  document: html,
164
- route: new URL(req.originalUrl ?? '/', server.resolvedUrls?.local[0]).toString(),
166
+ route: new URL(req.originalUrl ?? '/', baseUrl).toString(),
165
167
  serverContext: 'ssr',
166
168
  loadBundle: (uri) =>
167
169
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -12,7 +12,7 @@ import { promises as fsPromises } from 'node:fs';
12
12
  import { BuildOutputFile } from '../tools/esbuild/bundler-context';
13
13
  import { BuildOutputAsset } from '../tools/esbuild/bundler-execution-result';
14
14
  export declare function augmentAppWithServiceWorker(appRoot: string, workspaceRoot: string, outputPath: string, baseHref: string, ngswConfigPath?: string, inputputFileSystem?: typeof fsPromises, outputFileSystem?: typeof fsPromises): Promise<void>;
15
- export declare function augmentAppWithServiceWorkerEsbuild(workspaceRoot: string, configPath: string, baseHref: string, outputFiles: BuildOutputFile[], assetFiles: BuildOutputAsset[]): Promise<{
15
+ export declare function augmentAppWithServiceWorkerEsbuild(workspaceRoot: string, configPath: string, baseHref: string, indexHtml: string | undefined, outputFiles: BuildOutputFile[], assetFiles: BuildOutputAsset[]): Promise<{
16
16
  manifest: string;
17
17
  assetFiles: BuildOutputAsset[];
18
18
  }>;
@@ -159,12 +159,15 @@ async function augmentAppWithServiceWorker(appRoot, workspaceRoot, outputPath, b
159
159
  }
160
160
  exports.augmentAppWithServiceWorker = augmentAppWithServiceWorker;
161
161
  // This is currently used by the esbuild-based builder
162
- async function augmentAppWithServiceWorkerEsbuild(workspaceRoot, configPath, baseHref, outputFiles, assetFiles) {
162
+ async function augmentAppWithServiceWorkerEsbuild(workspaceRoot, configPath, baseHref, indexHtml, outputFiles, assetFiles) {
163
163
  // Read the configuration file
164
164
  let config;
165
165
  try {
166
166
  const configurationData = await node_fs_1.promises.readFile(configPath, 'utf-8');
167
167
  config = JSON.parse(configurationData);
168
+ if (indexHtml) {
169
+ config.index = indexHtml;
170
+ }
168
171
  }
169
172
  catch (error) {
170
173
  (0, error_1.assertIsError)(error);