Skip to content

Commit 2973f1f

Browse files
committed
refactor(@angular/build): collect and log build errors in library builder
Instead of throwing errors inside `buildAction` and `compileLibrary` during progress spinner execution, collect formatted diagnostic errors, warnings, and informational logs into `BuildActionResult` and log them via `context.logger` after `withProgress` completes, matching the behavior of the `application` builder.
1 parent 1f31103 commit 2973f1f

7 files changed

Lines changed: 350 additions & 197 deletions

File tree

‎packages/angular/build/src/builders/library/builder.ts‎

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { getSupportedBrowsers } from '../../utils/supported-browsers';
2424
import { assertCompatibleAngularVersion } from '../../utils/version';
2525
import type { BuildWatcher } from '../../utils/watcher';
2626
import { normalizeLibraryOptions } from './options';
27+
import type { BuildActionResult } from './pipeline/build-action';
2728
import { updateWatchedEntryPoints } from './pipeline/entry-points';
2829
import type { createComponentStylesheetBundlerForLibrary } from './pipeline/stylesheet-bundler';
2930
import { loadPackageJson } from './pipeline/utils';
@@ -50,12 +51,20 @@ export async function* executeLibraryBuilder(
5051
return;
5152
}
5253

53-
const [normalizedOptions] = await Promise.all([
54-
normalizeLibraryOptions(context, projectName, options),
55-
initializeHash(),
56-
// Purge old build disk cache
57-
purgeStaleBuildCache(context),
58-
]);
54+
let normalizedOptions: NormalizedLibraryOptions;
55+
try {
56+
[normalizedOptions] = await Promise.all([
57+
normalizeLibraryOptions(context, projectName, options),
58+
initializeHash(),
59+
// Purge old build disk cache
60+
purgeStaleBuildCache(context),
61+
]);
62+
} catch (error) {
63+
assertIsError(error);
64+
yield { success: false, error: error.message };
65+
66+
return;
67+
}
5968

6069
const {
6170
workspaceRoot,
@@ -185,6 +194,17 @@ export async function* executeLibraryBuilder(
185194
}
186195
}
187196

197+
/**
198+
* Executes a single build iteration with progress reporting, logs any resulting
199+
* messages, and registers newly discovered files with the watcher.
200+
*
201+
* @param message Progress spinner message to display while building.
202+
* @param actionContext The build action context and state.
203+
* @param withProgress Progress wrapper function (`withSpinner` or `withNoProgress`).
204+
* @param watcher Optional file watcher for watch mode.
205+
* @param buildAction The library build action function to execute.
206+
* @returns A promise resolving to the Architect `BuilderOutput`.
207+
*/
188208
async function executeBuild(
189209
message: string,
190210
actionContext: import('./pipeline/build-action').BuildActionContext,
@@ -196,13 +216,16 @@ async function executeBuild(
196216
const { context, watchedCompilationFiles, isWatchMode, options } = actionContext;
197217

198218
try {
199-
await withProgress(message, () => buildAction(actionContext));
200-
logBuildResult(context.logger, startTime, true, options.outputPath);
201-
if (isWatchMode) {
219+
const result = await withProgress(message, () => buildAction(actionContext));
220+
logMessages(context.logger, result);
221+
222+
const success = result.errors.length === 0;
223+
logBuildResult(context.logger, startTime, success, options.outputPath);
224+
if (success && isWatchMode) {
202225
logCumulativeDurations();
203226
}
204227

205-
return { success: true };
228+
return { success };
206229
} catch (error) {
207230
assertIsError(error);
208231
logBuildResult(context.logger, startTime, false);
@@ -300,6 +323,7 @@ async function* runWatchLoop(
300323
assertIsError(error);
301324
await buildState.singleProgramCache?.compilationInstance.update?.(changedFiles);
302325
buildState.hasEmittedManifests = false;
326+
303327
yield {
304328
success: false,
305329
error: `Failed to reload 'package.json': ${error.message}`,
@@ -343,8 +367,36 @@ async function* runWatchLoop(
343367
}
344368
}
345369

370+
/**
371+
* Logs informational, warning, and error messages produced during a build iteration.
372+
*
373+
* @param logger The Architect logger API.
374+
* @param result The build action result containing logs, warnings, and errors.
375+
*/
376+
function logMessages(
377+
logger: logging.LoggerApi,
378+
{ logs, warnings, errors }: BuildActionResult,
379+
): void {
380+
if (logs.length) {
381+
logger.info(logs.join('\n'));
382+
}
383+
384+
if (warnings.length) {
385+
logger.warn(warnings.join('\n'));
386+
}
387+
388+
if (errors.length) {
389+
logger.error(errors.join('\n'));
390+
}
391+
}
392+
346393
/**
347394
* Logs the build completion time and status.
395+
*
396+
* @param logger The Architect logger API.
397+
* @param startTime High-resolution timestamp recorded when the build iteration started.
398+
* @param success Whether the build iteration succeeded without errors.
399+
* @param outputPath Optional output directory path to log on successful builds.
348400
*/
349401
function logBuildResult(
350402
logger: logging.LoggerApi,

0 commit comments

Comments
 (0)