Skip to content

Commit 3bf270c

Browse files
authored
feat(core): Pass mapDir to rewriteSourcesHook (#908)
1 parent 97614c9 commit 3bf270c

File tree

4 files changed

+81
-4
lines changed

4 files changed

+81
-4
lines changed

packages/bundler-plugin-core/src/debug-id-upload.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,10 @@ async function prepareSourceMapForDebugIdUpload(
219219
}
220220

221221
if (map["sources"] && Array.isArray(map["sources"])) {
222-
map["sources"] = map["sources"].map((source: string) => rewriteSourcesHook(source, map));
222+
const mapDir = path.dirname(sourceMapPath);
223+
map["sources"] = map["sources"].map((source: string) =>
224+
rewriteSourcesHook(source, map, { mapDir })
225+
);
223226
}
224227

225228
try {

packages/bundler-plugin-core/src/types.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ export interface Options {
138138
/**
139139
* Hook to rewrite the `sources` field inside the source map before being uploaded to Sentry. Does not modify the actual source map.
140140
*
141+
* The hook receives the source path, the parsed source map object, and a context object containing `mapDir` -
142+
* the directory of the source map file, useful for resolving relative source paths.
143+
*
141144
* Defaults to making all sources relative to `process.cwd()` while building.
142145
*/
143146
rewriteSources?: RewriteSourcesHook;
@@ -427,7 +430,7 @@ export interface Options {
427430
}
428431

429432
// eslint-disable-next-line @typescript-eslint/no-explicit-any
430-
export type RewriteSourcesHook = (source: string, map: any) => string;
433+
export type RewriteSourcesHook = (source: string, map: any, context?: { mapDir: string }) => string;
431434

432435
export type ResolveSourceMapHook = (
433436
artifactPath: string,
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2+
import * as fs from "fs";
3+
import * as path from "path";
4+
import * as os from "os";
5+
import { prepareBundleForDebugIdUpload } from "../src/debug-id-upload";
6+
import type { RewriteSourcesHook } from "../src/types";
7+
import { Logger } from "../src";
8+
9+
describe("prepareBundleForDebugIdUpload", () => {
10+
let tmpDir: string;
11+
12+
beforeEach(() => {
13+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sentry-test-"));
14+
});
15+
16+
afterEach(() => {
17+
fs.rmSync(tmpDir, { recursive: true, force: true });
18+
});
19+
20+
it("passes mapDir context to rewriteSources hook", async () => {
21+
const bundleDir = path.join(tmpDir, "src");
22+
const uploadDir = path.join(tmpDir, "upload");
23+
fs.mkdirSync(bundleDir, { recursive: true });
24+
fs.mkdirSync(uploadDir, { recursive: true });
25+
26+
const debugId = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee";
27+
const bundlePath = path.join(bundleDir, "bundle.js");
28+
const mapPath = path.join(bundleDir, "bundle.js.map");
29+
30+
// Bundle with debug ID snippet and sourceMappingURL
31+
fs.writeFileSync(
32+
bundlePath,
33+
`"use strict";\n// some code\n;!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="${debugId}",e._sentryDebugIdIdentifier="sentry-dbid-${debugId}")}catch(e){}}();\n//# sourceMappingURL=bundle.js.map`
34+
);
35+
36+
// Source map file
37+
fs.writeFileSync(
38+
mapPath,
39+
JSON.stringify({
40+
version: 3,
41+
sources: ["../original/file.ts"],
42+
mappings: "AAAA",
43+
})
44+
);
45+
46+
const capturedContexts: Array<{ mapDir?: string } | undefined> = [];
47+
const rewriteHook: RewriteSourcesHook = (source, _map, context) => {
48+
capturedContexts.push(context);
49+
return source;
50+
};
51+
52+
const logger = {
53+
info: vi.fn(),
54+
warn: vi.fn(),
55+
error: vi.fn(),
56+
debug: vi.fn(),
57+
};
58+
59+
await prepareBundleForDebugIdUpload(
60+
bundlePath,
61+
uploadDir,
62+
0,
63+
logger as Logger,
64+
rewriteHook,
65+
undefined
66+
);
67+
68+
expect(capturedContexts).toHaveLength(1);
69+
expect(capturedContexts[0]!.mapDir).toBe(bundleDir);
70+
});
71+
});

packages/dev-utils/src/generate-documentation-table.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,9 @@ errorHandler: (err) => {
9595
},
9696
{
9797
name: "rewriteSources",
98-
type: "(source: string, map: any) => string",
98+
type: "(source: string, map: any, context?: { mapDir: string }) => string",
9999
fullDescription:
100-
"Hook to rewrite the `sources` field inside the source map before being uploaded to Sentry. Does not modify the actual source map. Effectively, this modifies how files inside the stacktrace will show up in Sentry.\n\nDefaults to making all sources relative to `process.cwd()` while building.",
100+
"Hook to rewrite the `sources` field inside the source map before being uploaded to Sentry. Does not modify the actual source map. Effectively, this modifies how files inside the stacktrace will show up in Sentry.\n\nThe `context.mapDir` parameter provides the directory path of the source map file, which is useful for resolving relative source paths (e.g. `path.resolve(context.mapDir, source)`).\n\nDefaults to making all sources relative to `process.cwd()` while building.",
101101
},
102102
{
103103
name: "resolveSourceMap",

0 commit comments

Comments
 (0)