fix(bundler): sourcemap sources should be relative to root, not output dir

When using `Bun.build()` with a `root` option and external sourcemaps,
the sourcemap `sources` paths were incorrectly relative to the output
directory instead of the specified root directory.

For example, with `root: "."` and `outdir: "./dist"`, source paths were
being generated as `"../src/index.ts"` (relative to `dist/src/`) instead
of `"src/index.ts"` (relative to root).

The fix changes both JS and CSS sourcemap generation to use `root_dir`
instead of `output_dir` when relativizing source file paths.

Fixes #3332

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Claude Bot
2026-01-15 01:06:42 +00:00
parent 22bebfc467
commit 792ee03e75
3 changed files with 70 additions and 2 deletions

View File

@@ -105,7 +105,7 @@ pub fn postProcessCSSChunk(ctx: GenerateChunkCtx, worker: *ThreadPool.Worker, ch
chunk.isolated_hash,
worker,
compile_results_for_source_map,
c.resolver.opts.output_dir,
c.resolver.opts.root_dir,
can_have_shifts,
);
}

View File

@@ -429,7 +429,7 @@ pub fn postProcessJSChunk(ctx: GenerateChunkCtx, worker: *ThreadPool.Worker, chu
chunk.isolated_hash,
worker,
compile_results_for_source_map,
c.resolver.opts.output_dir,
c.resolver.opts.root_dir,
can_have_shifts,
);
}

View File

@@ -0,0 +1,68 @@
import { describe, expect, test } from "bun:test";
import { tempDir } from "harness";
import path from "path";
describe("issue #3332 - sourcemap sources should be relative to root", () => {
test("JS sourcemap sources are relative to root, not output directory", async () => {
using dir = tempDir("issue-3332-js", {
"src/index.ts": `import { helper } from './nested/helper';
console.log(helper());`,
"src/nested/helper.ts": `export function helper() {
return 'hello';
}`,
});
const result = await Bun.build({
entrypoints: [path.join(String(dir), "src/index.ts")],
outdir: path.join(String(dir), "dist"),
root: String(dir),
sourcemap: "external",
});
expect(result.success).toBe(true);
// Find the sourcemap output
const sourcemapOutput = result.outputs.find(o => o.kind === "sourcemap");
expect(sourcemapOutput).toBeDefined();
// Parse the sourcemap
const mapContent = await sourcemapOutput!.text();
const map = JSON.parse(mapContent);
// Sources should be relative to root (the project directory), not output directory
// Expected: ["src/nested/helper.ts", "src/index.ts"] (or similar)
// Bug behavior: ["../src/nested/helper.ts", "../src/index.ts"] (relative to dist/src/)
for (const source of map.sources) {
expect(source).not.toMatch(/^\.\.\//);
expect(source).toMatch(/^src\//);
}
expect(map.sources).toContain("src/index.ts");
expect(map.sources).toContain("src/nested/helper.ts");
});
test("sourcemap sources without explicit root use cwd", async () => {
using dir = tempDir("issue-3332-no-root", {
"index.ts": `console.log('hello');`,
});
const result = await Bun.build({
entrypoints: [path.join(String(dir), "index.ts")],
outdir: path.join(String(dir), "dist"),
sourcemap: "external",
});
expect(result.success).toBe(true);
const sourcemapOutput = result.outputs.find(o => o.kind === "sourcemap");
expect(sourcemapOutput).toBeDefined();
const mapContent = await sourcemapOutput!.text();
const map = JSON.parse(mapContent);
// Sources should contain just the filename or a relative path, not "../"
for (const source of map.sources) {
expect(source).not.toMatch(/^\.\.\//);
}
});
});