Skip to content

Commit cd490df

Browse files
committed
fix(@angular/build): capture and report Rolldown warnings and errors in library builder
Updates `bundleEntryPoints` to capture Rolldown warning logs via `onLog` and bundling errors, returning them to `buildAction` so warnings are logged via the builder logger instead of `console.warn` and errors are properly surfaced.
1 parent 76dd17d commit cd490df

3 files changed

Lines changed: 87 additions & 22 deletions

File tree

‎packages/angular/build/src/builders/library/pipeline/build-action.ts‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,18 @@ export async function buildAction(actionContext: BuildActionContext): Promise<vo
152152
throw error;
153153
}
154154

155+
for (const warning of [...warnings, ...bundleOutput.warnings]) {
156+
context.logger.warn(warning);
157+
}
158+
159+
if (bundleOutput.errors.length > 0) {
160+
throw new Error(bundleOutput.errors.join('\n'));
161+
}
162+
155163
buildState.hasCompilationError = false;
156164
pendingChangedEsmFiles.clear();
157165
pendingChangedDtsFiles.clear();
158166

159-
for (const warning of warnings) {
160-
context.logger.warn(warning);
161-
}
162-
163167
filesToEmit.push(...bundleOutput.filesToEmit);
164168
for (const [name, bundleResult] of bundleOutput.bundleResults) {
165169
buildState.previousBundleResults.set(name, bundleResult);

‎packages/angular/build/src/builders/library/pipeline/bundler.ts‎

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ export interface BundleEntryPointsOutput {
3434

3535
/** Map of entry point names to their bundle results containing bundled module IDs. */
3636
bundleResults: Map<string, BundleResult>;
37+
38+
/** Warning messages emitted during bundling. */
39+
warnings: string[];
40+
41+
/** Error messages emitted during bundling. */
42+
errors: string[];
3743
}
3844

3945
/**
@@ -65,6 +71,12 @@ interface MultiBundleOutput {
6571

6672
/** Map of bundle entry names to the set of virtual module IDs included in the bundle. */
6773
moduleIdsByBundle: Map<string, Set<string>>;
74+
75+
/** Warning messages emitted during the bundle invocation. */
76+
warnings: string[];
77+
78+
/** Error messages emitted during the bundle invocation. */
79+
errors: string[];
6880
}
6981

7082
/**
@@ -85,7 +97,7 @@ export async function bundleEntryPoints(
8597
): Promise<BundleEntryPointsOutput> {
8698
const bundleResults = new Map<string, BundleResult>();
8799
if (items.length === 0) {
88-
return { filesToEmit: [], bundleResults };
100+
return { filesToEmit: [], bundleResults, warnings: [], errors: [] };
89101
}
90102

91103
const esmEntryPoints: NormalizedEntryPoint[] = [];
@@ -122,6 +134,8 @@ export async function bundleEntryPoints(
122134
return {
123135
filesToEmit: [...esmOutput.filesToEmit, ...dtsOutput.filesToEmit],
124136
bundleResults,
137+
warnings: [...esmOutput.warnings, ...dtsOutput.warnings],
138+
errors: [...esmOutput.errors, ...dtsOutput.errors],
125139
};
126140
}
127141

@@ -228,7 +242,10 @@ function createMemoryFileLoaderPlugin(
228242
* @param dir The destination output directory prefix.
229243
* @returns The processed multi-bundle output.
230244
*/
231-
function processRolldownOutput(output: RolldownOutput['output'], dir: string): MultiBundleOutput {
245+
function processRolldownOutput(
246+
output: RolldownOutput['output'],
247+
dir: string,
248+
): Pick<MultiBundleOutput, 'filesToEmit' | 'moduleIdsByBundle'> {
232249
const filesToEmit: MemoryOutputFile[] = [];
233250
const moduleIdsByBundle = new Map<string, Set<string>>();
234251
const chunksByFileName = new Map<string, OutputChunk>();
@@ -295,7 +312,6 @@ function processRolldownOutput(output: RolldownOutput['output'], dir: string): M
295312
* @param preserveSymlinks Whether to preserve symlinks during module resolution.
296313
* @param extension Output file extension ('mjs' or 'd.ts').
297314
* @param sourcemap Whether to emit sourcemaps.
298-
* @param findEntryPoint Lookup function to resolve chunk entry point ownership.
299315
* @returns A promise resolving to the multi-bundle output.
300316
*/
301317
async function executeMultiBundle(
@@ -307,19 +323,28 @@ async function executeMultiBundle(
307323
): Promise<MultiBundleOutput> {
308324
const isDts = extension === 'd.ts';
309325
const dir = isDts ? TYPES_OUTPUT_DIR : FESM_OUTPUT_DIR;
310-
const bundle = await rolldown({
311-
context: 'this',
312-
input,
313-
plugins,
314-
treeshake: false,
315-
resolve: { symlinks: !preserveSymlinks },
316-
checks: { circularDependency: false },
317-
experimental: {
318-
attachDebugInfo: 'none',
319-
},
320-
});
326+
const warnings: string[] = [];
327+
const errors: string[] = [];
328+
let bundle: Awaited<ReturnType<typeof rolldown>> | undefined;
321329

322330
try {
331+
bundle = await rolldown({
332+
context: 'this',
333+
input,
334+
plugins,
335+
treeshake: false,
336+
resolve: { symlinks: !preserveSymlinks },
337+
checks: { circularDependency: false },
338+
onLog(level, log) {
339+
if (level === 'warn') {
340+
warnings.push(log.message);
341+
}
342+
},
343+
experimental: {
344+
attachDebugInfo: 'none',
345+
},
346+
});
347+
323348
const { output } = await bundle.generate({
324349
format: 'es',
325350
dir,
@@ -330,9 +355,25 @@ async function executeMultiBundle(
330355
comments: { jsdoc: isDts, legal: true, annotation: true },
331356
});
332357

333-
return processRolldownOutput(output, dir);
358+
const { filesToEmit, moduleIdsByBundle } = processRolldownOutput(output, dir);
359+
360+
return {
361+
filesToEmit,
362+
moduleIdsByBundle,
363+
warnings,
364+
errors,
365+
};
366+
} catch (error) {
367+
errors.push(error instanceof Error ? error.message : String(error));
368+
369+
return {
370+
filesToEmit: [],
371+
moduleIdsByBundle: new Map(),
372+
warnings,
373+
errors,
374+
};
334375
} finally {
335-
await bundle.close();
376+
await bundle?.close();
336377
}
337378
}
338379

@@ -350,7 +391,7 @@ async function bundleAllEsm(
350391
options: NormalizedLibraryOptions,
351392
): Promise<MultiBundleOutput> {
352393
if (entryPoints.length === 0) {
353-
return { filesToEmit: [], moduleIdsByBundle: new Map() };
394+
return { filesToEmit: [], moduleIdsByBundle: new Map(), warnings: [], errors: [] };
354395
}
355396

356397
return executeMultiBundle(
@@ -376,7 +417,7 @@ async function bundleAllDts(
376417
options: NormalizedLibraryOptions,
377418
): Promise<MultiBundleOutput> {
378419
if (entryPoints.length === 0) {
379-
return { filesToEmit: [], moduleIdsByBundle: new Map() };
420+
return { filesToEmit: [], moduleIdsByBundle: new Map(), warnings: [], errors: [] };
380421
}
381422

382423
const dtsSourcemap = options.declarationMap;

‎packages/angular/build/src/builders/library/tests/behavior/build_spec.ts‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,25 @@ describeLibraryBuilder(executeLibraryBuilder, LIBRARY_BUILDER_INFO, (harness) =>
4747
}),
4848
);
4949
});
50+
51+
it('should log Rolldown bundler warnings', async () => {
52+
await harness.writeFile(
53+
'projects/lib/src/public-api.ts',
54+
`export function runDynamic(code: string) { return eval(code); }`,
55+
);
56+
57+
harness.useTarget('build', {
58+
...BASE_OPTIONS,
59+
});
60+
61+
const { result, logs } = await harness.executeOnce();
62+
expect(result?.success).toBeTrue();
63+
expect(logs).toContain(
64+
jasmine.objectContaining({
65+
level: 'warn',
66+
message: jasmine.stringContaining('eval'),
67+
}),
68+
);
69+
});
5070
});
5171
});

0 commit comments

Comments
 (0)