Skip to content

Commit 7bc20a7

Browse files
authored
fix: Replace existing debug ID comments (#730)
1 parent 2d796d7 commit 7bc20a7

File tree

12 files changed

+210
-6
lines changed

12 files changed

+210
-6
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ yarn-error.log
77
*.tgz
88

99
.nxcache
10+
packages/**/yarn.lock

packages/bundler-plugin-core/src/build-plugin-manager.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -457,8 +457,11 @@ export function createSentryBuildPluginManager(
457457
const tmpUploadFolder = await startSpan(
458458
{ name: "mkdtemp", scope: sentryScope },
459459
async () => {
460-
return await fs.promises.mkdtemp(
461-
path.join(os.tmpdir(), "sentry-bundler-plugin-upload-")
460+
return (
461+
process.env?.["SENTRY_TEST_OVERRIDE_TEMP_DIR"] ||
462+
(await fs.promises.mkdtemp(
463+
path.join(os.tmpdir(), "sentry-bundler-plugin-upload-")
464+
))
462465
);
463466
}
464467
);
@@ -586,7 +589,7 @@ export function createSentryBuildPluginManager(
586589
sentryScope.captureException('Error in "debugIdUploadPlugin" writeBundle hook');
587590
handleRecoverableError(e, false);
588591
} finally {
589-
if (folderToCleanUp) {
592+
if (folderToCleanUp && !process.env?.["SENTRY_TEST_OVERRIDE_TEMP_DIR"]) {
590593
void startSpan({ name: "cleanup", scope: sentryScope }, async () => {
591594
if (folderToCleanUp) {
592595
await fs.promises.rm(folderToCleanUp, { recursive: true, force: true });

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

+15-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export async function prepareBundleForDebugIdUpload(
5050

5151
const uniqueUploadName = `${debugId}-${chunkIndex}`;
5252

53-
bundleContent += `\n//# debugId=${debugId}`;
53+
bundleContent = addDebugIdToBundleSource(bundleContent, debugId);
5454
const writeSourceFilePromise = fs.promises.writeFile(
5555
path.join(uploadFolder, `${uniqueUploadName}.js`),
5656
bundleContent,
@@ -95,6 +95,20 @@ function determineDebugIdFromBundleSource(code: string): string | undefined {
9595
}
9696
}
9797

98+
const SPEC_LAST_DEBUG_ID_REGEX = /\/\/# debugId=([a-fA-F0-9-]+)(?![\s\S]*\/\/# debugId=)/m;
99+
100+
function hasSpecCompliantDebugId(bundleSource: string): boolean {
101+
return SPEC_LAST_DEBUG_ID_REGEX.test(bundleSource);
102+
}
103+
104+
function addDebugIdToBundleSource(bundleSource: string, debugId: string): string {
105+
if (hasSpecCompliantDebugId(bundleSource)) {
106+
return bundleSource.replace(SPEC_LAST_DEBUG_ID_REGEX, `//# debugId=${debugId}`);
107+
} else {
108+
return `${bundleSource}\n//# debugId=${debugId}`;
109+
}
110+
}
111+
98112
/**
99113
* Applies a set of heuristics to find the source map for a particular bundle.
100114
*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import * as path from "path";
2+
import * as fs from "fs";
3+
import * as os from "os";
4+
import { describeNode18Plus } from "../../utils/testIf";
5+
import { execSync } from "child_process";
6+
7+
function createTempDir() {
8+
return fs.mkdtempSync(path.join(os.tmpdir(), "sentry-bundler-plugin-upload-"));
9+
}
10+
11+
const SPEC_DEBUG_ID_REGEX = /\/\/# debugId=([a-fA-F0-9-]+)/g;
12+
13+
function countDebugIdComments(source: string): number {
14+
const matches = source.match(SPEC_DEBUG_ID_REGEX);
15+
if (matches) {
16+
return matches.length;
17+
}
18+
return 0;
19+
}
20+
21+
function getSingleJavaScriptSourceFileFromDirectory(
22+
dir: string,
23+
fileExtension = ".js"
24+
): string | undefined {
25+
const files = fs.readdirSync(dir);
26+
const jsFiles = files.filter((file) => file.endsWith(fileExtension));
27+
if (jsFiles.length === 1) {
28+
return fs.readFileSync(path.join(dir, jsFiles[0] as string), "utf-8");
29+
}
30+
return undefined;
31+
}
32+
33+
describeNode18Plus("vite 6 bundle", () => {
34+
const viteRoot = path.join(__dirname, "input", "vite6");
35+
const tempDir = createTempDir();
36+
37+
beforeEach(() => {
38+
execSync("yarn install", { cwd: viteRoot, stdio: "inherit" });
39+
execSync("yarn vite build", {
40+
cwd: viteRoot,
41+
stdio: "inherit",
42+
env: { ...process.env, SENTRY_TEST_OVERRIDE_TEMP_DIR: tempDir },
43+
});
44+
});
45+
46+
test("check vite 6 bundle", () => {
47+
const source = getSingleJavaScriptSourceFileFromDirectory(tempDir);
48+
expect(source).toBeDefined();
49+
const debugIds = countDebugIdComments(source as string);
50+
expect(debugIds).toBe(1);
51+
});
52+
53+
afterEach(() => {
54+
fs.rmSync(tempDir, { recursive: true, force: true });
55+
});
56+
});
57+
58+
describeNode18Plus("webpack 5 bundle", () => {
59+
const viteRoot = path.join(__dirname, "input", "webpack5");
60+
const tempDir = createTempDir();
61+
62+
beforeEach(() => {
63+
execSync("yarn install", { cwd: viteRoot, stdio: "inherit" });
64+
execSync("yarn webpack build", {
65+
cwd: viteRoot,
66+
stdio: "inherit",
67+
env: { ...process.env, SENTRY_TEST_OVERRIDE_TEMP_DIR: tempDir },
68+
});
69+
});
70+
71+
test("check webpack 5 bundle", () => {
72+
const source = getSingleJavaScriptSourceFileFromDirectory(tempDir);
73+
expect(source).toBeDefined();
74+
const debugIds = countDebugIdComments(source as string);
75+
expect(debugIds).toBe(1);
76+
});
77+
78+
afterEach(() => {
79+
fs.rmSync(tempDir, { recursive: true, force: true });
80+
});
81+
});
82+
83+
describeNode18Plus("rollup bundle", () => {
84+
const viteRoot = path.join(__dirname, "input", "rollup4");
85+
const tempDir = createTempDir();
86+
87+
beforeEach(() => {
88+
execSync("yarn install", { cwd: viteRoot, stdio: "inherit" });
89+
execSync("yarn rollup --config rollup.config.js", {
90+
cwd: viteRoot,
91+
stdio: "inherit",
92+
env: { ...process.env, SENTRY_TEST_OVERRIDE_TEMP_DIR: tempDir },
93+
});
94+
});
95+
96+
test("check rollup bundle", () => {
97+
const source = getSingleJavaScriptSourceFileFromDirectory(tempDir);
98+
expect(source).toBeDefined();
99+
const debugIds = countDebugIdComments(source as string);
100+
expect(debugIds).toBe(1);
101+
});
102+
103+
afterEach(() => {
104+
fs.rmSync(tempDir, { recursive: true, force: true });
105+
});
106+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// eslint-disable-next-line no-console
2+
console.log("Hello world");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"type": "module",
3+
"dependencies": {
4+
"rollup": "^4"
5+
}
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { defineConfig } from "rollup";
2+
import { sentryRollupPlugin } from "@sentry/rollup-plugin";
3+
import { join } from "path";
4+
5+
const __dirname = new URL(".", import.meta.url).pathname;
6+
7+
export default defineConfig({
8+
input: { index: join(__dirname, "..", "bundle.js") },
9+
output: {
10+
dir: join(__dirname, "..", "..", "out", "rollup4"),
11+
sourcemap: true,
12+
sourcemapDebugIds: true,
13+
},
14+
plugins: [sentryRollupPlugin({ telemetry: false })],
15+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"dependencies": {
3+
"vite": "^6"
4+
}
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { defineConfig } from "vite";
2+
import { sentryVitePlugin } from "@sentry/vite-plugin";
3+
import { join } from "path";
4+
5+
export default defineConfig({
6+
clearScreen: false,
7+
mode: "production",
8+
build: {
9+
sourcemap: true,
10+
outDir: join(__dirname, "..", "..", "out", "vite6"),
11+
rollupOptions: {
12+
input: { index: join(__dirname, "..", "bundle.js") },
13+
output: {
14+
format: "cjs",
15+
entryFileNames: "[name].js",
16+
sourcemapDebugIds: true,
17+
},
18+
},
19+
},
20+
plugins: [sentryVitePlugin({ telemetry: false })],
21+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "module",
3+
"dependencies": {
4+
"webpack": "^5",
5+
"webpack-cli": "^6"
6+
}
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { sentryWebpackPlugin } from "@sentry/webpack-plugin";
2+
import { join } from "path";
3+
4+
const __dirname = new URL(".", import.meta.url).pathname;
5+
6+
export default {
7+
devtool: "source-map-debugids",
8+
cache: false,
9+
entry: { index: join(__dirname, "..", "bundle.js") },
10+
output: {
11+
path: join(__dirname, "..", "..", "out", "webpack5"),
12+
library: {
13+
type: "commonjs",
14+
},
15+
},
16+
mode: "production",
17+
plugins: [sentryWebpackPlugin({ telemetry: false })],
18+
};

packages/integration-tests/utils/testIf.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const [NODE_MAJOR_VERSION] = process.version.replace("v", "").split(".").map(Number) as [number];
2+
13
// eslint-disable-next-line no-undef
24
export function testIf(condition: boolean): jest.It {
35
if (condition) {
@@ -15,7 +17,11 @@ export function testIf(condition: boolean): jest.It {
1517
*/
1618
// eslint-disable-next-line @typescript-eslint/no-explicit-any, no-undef, @typescript-eslint/no-unsafe-assignment
1719
export const testIfNodeMajorVersionIsLessThan18: jest.It = function () {
18-
const nodejsMajorversion = process.version.split(".")[0]?.slice(1);
19-
return testIf(!nodejsMajorversion || parseInt(nodejsMajorversion) < 18);
20+
return testIf(NODE_MAJOR_VERSION < 18);
2021
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2122
} as any;
23+
24+
// eslint-disable-next-line no-undef
25+
export const describeNode18Plus: jest.Describe =
26+
// eslint-disable-next-line no-undef
27+
NODE_MAJOR_VERSION >= 18 ? describe : describe.skip;

0 commit comments

Comments
 (0)