Skip to content

Commit d09ed80

Browse files
author
Luca Forstner
authored
feat(webpack): Generate deterministic debug IDs (#321)
1 parent db8e347 commit d09ed80

File tree

11 files changed

+204
-3
lines changed

11 files changed

+204
-3
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,4 +398,6 @@ export function getDebugIdSnippet(debugId: string): string {
398398
return `;!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="${debugId}",e._sentryDebugIdIdentifier="sentry-dbid-${debugId}")}catch(e){}}();`;
399399
}
400400

401+
export { stringToUUID } from "./utils";
402+
401403
export type { Options } from "./types";
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { sentryRollupPlugin } from "@sentry/rollup-plugin";
2+
import * as path from "path";
3+
import * as rollup from "rollup";
4+
import pluginOptions from "./plugin-options";
5+
6+
void rollup
7+
.rollup({
8+
input: {
9+
index: path.join(__dirname, "input", "index.js"),
10+
},
11+
plugins: [sentryRollupPlugin(pluginOptions)],
12+
})
13+
.then((bundle) =>
14+
bundle.write({
15+
dir: path.join(__dirname, "out", "rollup"),
16+
format: "cjs",
17+
exports: "named",
18+
})
19+
);
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { sentryVitePlugin } from "@sentry/vite-plugin";
2+
import * as path from "path";
3+
import * as vite from "vite";
4+
import pluginOptions from "./plugin-options";
5+
6+
void vite.build({
7+
clearScreen: false,
8+
build: {
9+
outDir: path.join(__dirname, "out", "vite"),
10+
rollupOptions: {
11+
input: {
12+
index: path.join(__dirname, "input", "index.js"),
13+
},
14+
output: {
15+
format: "cjs",
16+
entryFileNames: "[name].js",
17+
},
18+
},
19+
},
20+
plugins: [sentryVitePlugin(pluginOptions)],
21+
});
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { sentryWebpackPlugin } from "@sentry/webpack-plugin";
2+
import * as path from "path";
3+
import { default as webpack4 } from "webpack4";
4+
import pluginOptions from "./plugin-options";
5+
6+
webpack4(
7+
{
8+
mode: "production",
9+
entry: {
10+
index: path.join(__dirname, "input", "index.js"),
11+
},
12+
cache: false,
13+
output: {
14+
path: path.join(__dirname, "out", "webpack4"),
15+
libraryTarget: "commonjs",
16+
},
17+
target: "node", // needed for webpack 4 so we can access node api
18+
plugins: [sentryWebpackPlugin(pluginOptions)],
19+
},
20+
(err) => {
21+
if (err) {
22+
throw err;
23+
}
24+
}
25+
);
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { sentryWebpackPlugin } from "@sentry/webpack-plugin";
2+
import * as path from "path";
3+
import { webpack as webpack5 } from "webpack5";
4+
import pluginOptions from "./plugin-options";
5+
6+
webpack5(
7+
{
8+
cache: false,
9+
entry: {
10+
index: path.join(__dirname, "input", "index.js"),
11+
},
12+
output: {
13+
path: path.join(__dirname, "out", "webpack5"),
14+
library: {
15+
type: "commonjs",
16+
},
17+
},
18+
mode: "production",
19+
plugins: [sentryWebpackPlugin(pluginOptions)],
20+
},
21+
(err) => {
22+
if (err) {
23+
throw err;
24+
}
25+
}
26+
);
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/* eslint-disable jest/no-standalone-expect */
2+
/* eslint-disable jest/expect-expect */
3+
import childProcess from "child_process";
4+
import path from "path";
5+
import fs from "fs/promises";
6+
7+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
8+
const nodejsMajorversion = process.version.split(".")[0]!.slice(1);
9+
10+
function executeAndGetDebugIds(bundlePath: string): string[] {
11+
const processOutput = childProcess.execSync(`node ${bundlePath}`, { encoding: "utf-8" });
12+
const debugIdMap = JSON.parse(processOutput) as Record<string, string>;
13+
return Object.values(debugIdMap);
14+
}
15+
16+
beforeEach(async () => {
17+
await fs.writeFile(
18+
path.join(__dirname, "input", "dynamic-variable.js"),
19+
`global.dynamicVariable = 1;`
20+
);
21+
});
22+
23+
afterEach(async () => {
24+
await fs.unlink(path.join(__dirname, "input", "dynamic-variable.js"));
25+
});
26+
27+
describe("Same debug IDs for multiple identical builds", () => {
28+
const bundlers = ["rollup", "vite", "webpack5"];
29+
30+
if (parseInt(nodejsMajorversion) < 18) {
31+
bundlers.push("webpack4");
32+
}
33+
34+
test.each(bundlers)(
35+
"%s",
36+
(bundler) => {
37+
// build
38+
childProcess.execSync(`yarn ts-node ${path.join(__dirname, `build-${bundler}.ts`)}`);
39+
40+
const debugIds1 = executeAndGetDebugIds(path.join(__dirname, "out", bundler, "index.js"));
41+
42+
// rebuild
43+
childProcess.execSync(`yarn ts-node ${path.join(__dirname, `build-${bundler}.ts`)}`);
44+
45+
const debugIds2 = executeAndGetDebugIds(path.join(__dirname, "out", bundler, "index.js"));
46+
47+
expect(debugIds1).toStrictEqual(debugIds2);
48+
},
49+
20_000
50+
);
51+
});
52+
53+
describe("Different debug IDs for different builds", () => {
54+
const bundlers = ["rollup", "vite", "webpack5"];
55+
56+
if (parseInt(nodejsMajorversion) < 18) {
57+
bundlers.push("webpack4");
58+
}
59+
60+
test.each(bundlers)(
61+
"%s",
62+
async (bundler) => {
63+
// build
64+
childProcess.execSync(`yarn ts-node ${path.join(__dirname, `build-${bundler}.ts`)}`);
65+
66+
const debugIds1 = executeAndGetDebugIds(path.join(__dirname, "out", bundler, "index.js"));
67+
68+
await fs.writeFile(
69+
path.join(__dirname, "input", "dynamic-variable.js"),
70+
`global.dynamicVariable = 2;`
71+
);
72+
73+
// rebuild
74+
childProcess.execSync(`yarn ts-node ${path.join(__dirname, `build-${bundler}.ts`)}`);
75+
76+
const debugIds2 = executeAndGetDebugIds(path.join(__dirname, "out", bundler, "index.js"));
77+
78+
expect(debugIds1).not.toEqual(debugIds2);
79+
},
80+
20_000
81+
);
82+
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dynamic-variable.js
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import "./dynamic-variable";
2+
3+
// eslint-disable-next-line no-console
4+
console.log(JSON.stringify(global._sentryDebugIds));
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export default {
2+
telemetry: false,
3+
release: { name: "release", create: false },
4+
};

packages/integration-tests/scripts/run-fixture-setups.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,8 @@ const fixturePaths = fs
66
.map((fixtureDir) => path.join(__dirname, "..", "fixtures", fixtureDir));
77

88
fixturePaths.forEach((fixturePath) => {
9-
require(path.join(fixturePath, "setup.ts"));
9+
const setupScriptPath = path.join(fixturePath, "setup.ts");
10+
if (fs.existsSync(setupScriptPath)) {
11+
require(setupScriptPath);
12+
}
1013
});

0 commit comments

Comments
 (0)