From ca0842b7d9cfbedd46a1f5798a744455164f5a50 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Thu, 1 Oct 2026 15:26:28 +0000 Subject: [PATCH 1/2] fix(@angular/build): resolve library bundle sourcemap sources relative to output directory Configure `cwd` and `sourcemapPathTransform` when generating FESM and declaration bundles in the library builder so that emitted sourcemap `sources` entries are computed relative to the actual output directory. --- .../src/builders/library/pipeline/bundler.ts | 33 +++++++++++++------ .../library/tests/behavior/build_spec.ts | 8 ++++- .../tests/options/declaration-map_spec.ts | 13 +++++--- 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/packages/angular/build/src/builders/library/pipeline/bundler.ts b/packages/angular/build/src/builders/library/pipeline/bundler.ts index d04996ec7ac4..938dff79b628 100644 --- a/packages/angular/build/src/builders/library/pipeline/bundler.ts +++ b/packages/angular/build/src/builders/library/pipeline/bundler.ts @@ -292,24 +292,35 @@ function processRolldownOutput(output: RolldownOutput['output'], dir: string): M * * @param input Map of bundle names to virtual entry file paths. * @param plugins Rolldown plugins to use during bundling. - * @param preserveSymlinks Whether to preserve symlinks during module resolution. * @param extension Output file extension ('mjs' or 'd.ts'). - * @param sourcemap Whether to emit sourcemaps. - * @param findEntryPoint Lookup function to resolve chunk entry point ownership. + * @param options The normalized library options. * @returns A promise resolving to the multi-bundle output. */ async function executeMultiBundle( input: Record, plugins: RolldownPluginOption[], - preserveSymlinks: boolean, extension: 'mjs' | 'd.ts', - sourcemap: boolean, + options: NormalizedLibraryOptions, ): Promise { + const { workspaceRoot, preserveSymlinks, declarationMap, outputPath } = options; const isDts = extension === 'd.ts'; - const dir = isDts ? TYPES_OUTPUT_DIR : FESM_OUTPUT_DIR; + const relativeOutputPath = path.posix.relative(outputPath, workspaceRoot); + + let sourcemap: boolean; + let dir: string; + if (isDts) { + dir = TYPES_OUTPUT_DIR; + sourcemap = declarationMap; + } else { + dir = FESM_OUTPUT_DIR; + // FESM (.mjs) sourcemaps are always enabled. + sourcemap = true; + } + const bundle = await rolldown({ context: 'this', input, + cwd: workspaceRoot, plugins, treeshake: false, resolve: { symlinks: !preserveSymlinks }, @@ -326,6 +337,7 @@ async function executeMultiBundle( entryFileNames: `[name].${extension}`, chunkFileNames: `[name]-[hash].${extension}`, sourcemap, + sourcemapPathTransform: (sourcePath) => path.posix.join(relativeOutputPath, sourcePath), hoistTransitiveImports: false, comments: { jsdoc: isDts, legal: true, annotation: true }, }); @@ -356,9 +368,8 @@ async function bundleAllEsm( return executeMultiBundle( resolveEntryInputMap(entryPoints, false), [createMemoryFileLoaderPlugin(esmFiles, ESM_EXTENSIONS, true)], - options.preserveSymlinks, 'mjs', - true, + options, ); } @@ -389,10 +400,13 @@ async function bundleAllDts( dtsInput: true, tsconfig: false, sourcemap: dtsSourcemap, + generator: 'oxc', }); + const dtsPlugins = rawDtsPlugins.filter( (plugin) => plugin.name !== 'rolldown-plugin-dts:resolver', ); + assert( dtsPlugins.length < rawDtsPlugins.length, 'Expected "rolldown-plugin-dts:resolver" plugin to be present in rolldown-plugin-dts.', @@ -401,8 +415,7 @@ async function bundleAllDts( return executeMultiBundle( resolveEntryInputMap(entryPoints, true), [createMemoryFileLoaderPlugin(dtsFiles, DTS_EXTENSIONS, dtsSourcemap), ...dtsPlugins], - options.preserveSymlinks, 'd.ts', - dtsSourcemap, + options, ); } diff --git a/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts b/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts index 4e817babf944..e6029ffa46b6 100644 --- a/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts +++ b/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ +import { join } from 'node:path'; import { executeLibraryBuilder } from '../../builder'; import { BASE_OPTIONS, LIBRARY_BUILDER_INFO, describeLibraryBuilder } from '../setup'; @@ -21,11 +22,16 @@ describeLibraryBuilder(executeLibraryBuilder, LIBRARY_BUILDER_INFO, (harness) => expect(result?.success).toBeTrue(); harness.expectFile('dist/lib/fesm2022/lib.mjs').toExist(); - expect(harness.hasFile('dist/lib/fesm2022/lib.mjs')).toBeTrue(); + harness.expectFile('dist/lib/fesm2022/lib.mjs').toExist(); const fesmContent = harness.readFile('dist/lib/fesm2022/lib.mjs'); expect(fesmContent).toContain('LibComponent'); expect(fesmContent).toContain('ɵcmp'); + harness.expectFile('dist/lib/fesm2022/lib.mjs.map').toExist(); + const fesmMap = JSON.parse(harness.readFile('dist/lib/fesm2022/lib.mjs.map')); + expect(fesmMap.sources).toContain('../../../projects/lib/src/lib/lib.component.ts'); + harness.expectFile(join('dist/lib/fesm2022', fesmMap.sources[0])).toExist(); + harness.expectFile('dist/lib/types/lib.d.ts').toExist(); const dtsContent = harness.readFile('dist/lib/types/lib.d.ts'); expect(dtsContent).toContain('LibComponent'); diff --git a/packages/angular/build/src/builders/library/tests/options/declaration-map_spec.ts b/packages/angular/build/src/builders/library/tests/options/declaration-map_spec.ts index 6ff112ac3912..a37e2f0dd255 100644 --- a/packages/angular/build/src/builders/library/tests/options/declaration-map_spec.ts +++ b/packages/angular/build/src/builders/library/tests/options/declaration-map_spec.ts @@ -8,6 +8,7 @@ import { executeLibraryBuilder } from '../../builder'; import { BASE_OPTIONS, LIBRARY_BUILDER_INFO, describeLibraryBuilder } from '../setup'; +import { join } from 'node:path'; describeLibraryBuilder(executeLibraryBuilder, LIBRARY_BUILDER_INFO, (harness) => { describe('Option: "declarationMap"', () => { @@ -20,9 +21,9 @@ describeLibraryBuilder(executeLibraryBuilder, LIBRARY_BUILDER_INFO, (harness) => expect(result?.success).toBeTrue(); // FESM sourcemaps are always enabled - expect(harness.hasFile('dist/lib/fesm2022/lib.mjs.map')).toBeTrue(); + harness.expectFile('dist/lib/fesm2022/lib.mjs.map').toExist(); // DTS sourcemaps are disabled by default - expect(harness.hasFile('dist/lib/types/lib.d.ts.map')).toBeFalse(); + harness.expectFile('dist/lib/types/lib.d.ts.map').toNotExist(); }); it('should emit declaration sourcemaps when declarationMap is true', async () => { @@ -35,9 +36,13 @@ describeLibraryBuilder(executeLibraryBuilder, LIBRARY_BUILDER_INFO, (harness) => expect(result?.success).toBeTrue(); // FESM sourcemaps are always enabled - expect(harness.hasFile('dist/lib/fesm2022/lib.mjs.map')).toBeTrue(); + harness.expectFile('dist/lib/fesm2022/lib.mjs.map').toExist(); + // DTS sourcemaps should be generated - expect(harness.hasFile('dist/lib/types/lib.d.ts.map')).toBeTrue(); + harness.expectFile('dist/lib/types/lib.d.ts.map').toExist(); + const dtsMap = JSON.parse(harness.readFile('dist/lib/types/lib.d.ts.map')); + expect(dtsMap.sources).toContain('../../../projects/lib/src/lib/lib.component.ts'); + harness.expectFile(join('dist/lib/types', dtsMap.sources[0])).toExist(); }); }); }); From b6017cf7113b5e4082130aa6d3b28cbce7b8e8e9 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Fri, 2 Oct 2026 19:00:09 +0000 Subject: [PATCH 2/2] fixup! fix(@angular/build): resolve library bundle sourcemap sources relative to output directory --- .../angular/build/src/builders/library/pipeline/bundler.ts | 5 ++--- .../build/src/builders/library/tests/behavior/build_spec.ts | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/angular/build/src/builders/library/pipeline/bundler.ts b/packages/angular/build/src/builders/library/pipeline/bundler.ts index 938dff79b628..3f47b45548d6 100644 --- a/packages/angular/build/src/builders/library/pipeline/bundler.ts +++ b/packages/angular/build/src/builders/library/pipeline/bundler.ts @@ -304,10 +304,10 @@ async function executeMultiBundle( ): Promise { const { workspaceRoot, preserveSymlinks, declarationMap, outputPath } = options; const isDts = extension === 'd.ts'; - const relativeOutputPath = path.posix.relative(outputPath, workspaceRoot); let sourcemap: boolean; let dir: string; + if (isDts) { dir = TYPES_OUTPUT_DIR; sourcemap = declarationMap; @@ -333,11 +333,10 @@ async function executeMultiBundle( try { const { output } = await bundle.generate({ format: 'es', - dir, + dir: path.join(outputPath, dir), entryFileNames: `[name].${extension}`, chunkFileNames: `[name]-[hash].${extension}`, sourcemap, - sourcemapPathTransform: (sourcePath) => path.posix.join(relativeOutputPath, sourcePath), hoistTransitiveImports: false, comments: { jsdoc: isDts, legal: true, annotation: true }, }); diff --git a/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts b/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts index e6029ffa46b6..a7b3828cbbbc 100644 --- a/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts +++ b/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts @@ -21,7 +21,6 @@ describeLibraryBuilder(executeLibraryBuilder, LIBRARY_BUILDER_INFO, (harness) => expect(result?.error).toBeUndefined(); expect(result?.success).toBeTrue(); - harness.expectFile('dist/lib/fesm2022/lib.mjs').toExist(); harness.expectFile('dist/lib/fesm2022/lib.mjs').toExist(); const fesmContent = harness.readFile('dist/lib/fesm2022/lib.mjs'); expect(fesmContent).toContain('LibComponent');