Skip to content

Commit ab98b4f

Browse files
committed
test: added testing fixtures
1 parent ef6f4bb commit ab98b4f

7 files changed

Lines changed: 223 additions & 0 deletions

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { sentryVitePlugin } from "@sentry/vite-plugin";
2+
import * as path from "path";
3+
import * as vite from "vite";
4+
5+
const inputDir = path.join(__dirname, "input");
6+
7+
void vite.build({
8+
clearScreen: false,
9+
root: inputDir,
10+
build: {
11+
sourcemap: true,
12+
outDir: path.join(__dirname, "out", "with-plugin"),
13+
emptyOutDir: true,
14+
rollupOptions: {
15+
input: {
16+
index: path.join(inputDir, "index.html"),
17+
page1: path.join(inputDir, "page1.html"),
18+
page2: path.join(inputDir, "page2.html"),
19+
},
20+
},
21+
},
22+
plugins: [
23+
sentryVitePlugin({
24+
telemetry: false,
25+
// Empty options - the issue says options don't affect the results
26+
}),
27+
],
28+
});
29+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import * as path from "path";
2+
import * as vite from "vite";
3+
4+
const inputDir = path.join(__dirname, "input");
5+
6+
void vite.build({
7+
clearScreen: false,
8+
root: inputDir,
9+
build: {
10+
sourcemap: true,
11+
outDir: path.join(__dirname, "out", "without-plugin"),
12+
emptyOutDir: true,
13+
rollupOptions: {
14+
input: {
15+
index: path.join(inputDir, "index.html"),
16+
page1: path.join(inputDir, "page1.html"),
17+
page2: path.join(inputDir, "page2.html"),
18+
},
19+
},
20+
},
21+
plugins: [],
22+
});
23+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Index Page</title>
6+
</head>
7+
<body>
8+
<h1>Index Page - No Scripts</h1>
9+
<!-- This page has no scripts -->
10+
</body>
11+
</html>
12+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Page 1</title>
6+
</head>
7+
<body>
8+
<h1>Page 1 - With Shared Module</h1>
9+
<script type="module" src="./shared-module.js"></script>
10+
</body>
11+
</html>
12+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Page 2</title>
6+
</head>
7+
<body>
8+
<h1>Page 2 - With Shared Module</h1>
9+
<script type="module" src="./shared-module.js"></script>
10+
</body>
11+
</html>
12+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// This is a shared module that is used by multiple HTML pages
2+
export function greet(name) {
3+
// eslint-disable-next-line no-console
4+
console.log(`Hello, ${String(name)}!`);
5+
}
6+
7+
export const VERSION = "1.0.0";
8+
9+
// Side effect: greet on load
10+
greet("World");
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/**
2+
* Test for GitHub Issue #829:
3+
* sentryVitePlugin creates unnecessary JS modules for each index page
4+
*
5+
* In a Vite multi-page app (MPA), sentryVitePlugin causes "vite build" to emit
6+
* a separate, unique, unexpected JS module for each index page.
7+
*
8+
* Expected: The plugin should add metadata to generated modules but should NOT
9+
* rework the import graph, create new modules, or add script tags to pages
10+
* that didn't have them in the first place.
11+
*
12+
* Actual: A unique module is generated for every HTML page in rollup.options.input.
13+
* Pages that had been sharing modules will instead load a page-specific module
14+
* that imports the shared code. Pages that didn't contain ANY scripts will now have one.
15+
*/
16+
import childProcess from "child_process";
17+
import fs from "fs";
18+
import path from "path";
19+
20+
function getAssetFiles(outDir: string): string[] {
21+
const assetsDir = path.join(outDir, "assets");
22+
if (!fs.existsSync(assetsDir)) {
23+
return [];
24+
}
25+
return fs.readdirSync(assetsDir).filter((file) => file.endsWith(".js"));
26+
}
27+
28+
function getScriptTagsFromHtml(htmlPath: string): string[] {
29+
if (!fs.existsSync(htmlPath)) {
30+
return [];
31+
}
32+
const content = fs.readFileSync(htmlPath, "utf-8");
33+
const scriptMatches = content.match(/<script[^>]*>/g) || [];
34+
return scriptMatches;
35+
}
36+
37+
describe("Vite MPA Extra Modules Issue (#829)", () => {
38+
const outWithoutPlugin = path.join(__dirname, "out", "without-plugin");
39+
const outWithPlugin = path.join(__dirname, "out", "with-plugin");
40+
41+
beforeAll(() => {
42+
// Clean output directories
43+
if (fs.existsSync(outWithoutPlugin)) {
44+
fs.rmSync(outWithoutPlugin, { recursive: true });
45+
}
46+
if (fs.existsSync(outWithPlugin)) {
47+
fs.rmSync(outWithPlugin, { recursive: true });
48+
}
49+
50+
// Build without plugin
51+
childProcess.execSync(
52+
`yarn ts-node ${path.join(__dirname, "build-vite-without-plugin.ts")}`,
53+
{ encoding: "utf-8", stdio: "inherit" }
54+
);
55+
56+
// Build with plugin
57+
childProcess.execSync(
58+
`yarn ts-node ${path.join(__dirname, "build-vite-with-plugin.ts")}`,
59+
{ encoding: "utf-8", stdio: "inherit" }
60+
);
61+
}, 60_000);
62+
63+
it("should not create extra JS modules when sentry plugin is enabled", () => {
64+
const assetsWithoutPlugin = getAssetFiles(outWithoutPlugin);
65+
const assetsWithPlugin = getAssetFiles(outWithPlugin);
66+
67+
console.log("Assets without plugin:", assetsWithoutPlugin);
68+
console.log("Assets with plugin:", assetsWithPlugin);
69+
70+
// The number of JS files should be the same (or very close)
71+
// With the bug, the plugin creates extra modules like index.js, page1.js, page2.js
72+
// for each HTML entry point
73+
expect(assetsWithPlugin.length).toBeLessThanOrEqual(assetsWithoutPlugin.length + 1);
74+
});
75+
76+
it("should not add script tags to HTML pages that had none", () => {
77+
// index.html originally has no scripts
78+
const indexWithoutPlugin = getScriptTagsFromHtml(
79+
path.join(outWithoutPlugin, "index.html")
80+
);
81+
const indexWithPlugin = getScriptTagsFromHtml(
82+
path.join(outWithPlugin, "index.html")
83+
);
84+
85+
console.log("index.html scripts without plugin:", indexWithoutPlugin);
86+
console.log("index.html scripts with plugin:", indexWithPlugin);
87+
88+
// The number of script tags should be the same
89+
// With the bug, index.html gets a script tag added even though it had none
90+
expect(indexWithPlugin.length).toBe(indexWithoutPlugin.length);
91+
});
92+
93+
it("should preserve shared module imports without creating page-specific wrappers", () => {
94+
// page1.html and page2.html should both reference the same shared module
95+
// not page-specific modules
96+
const page1WithPlugin = fs.readFileSync(
97+
path.join(outWithPlugin, "page1.html"),
98+
"utf-8"
99+
);
100+
const page2WithPlugin = fs.readFileSync(
101+
path.join(outWithPlugin, "page2.html"),
102+
"utf-8"
103+
);
104+
105+
// Extract the JS file references
106+
const page1ScriptMatch = page1WithPlugin.match(/src="([^"]+\.js)"/);
107+
const page2ScriptMatch = page2WithPlugin.match(/src="([^"]+\.js)"/);
108+
109+
console.log("page1 script src:", page1ScriptMatch?.[1]);
110+
console.log("page2 script src:", page2ScriptMatch?.[1]);
111+
112+
if (page1ScriptMatch && page2ScriptMatch) {
113+
// Both pages should reference the same shared module, not page-specific ones
114+
// With the bug, page1.html references page1-xxx.js and page2.html references page2-xxx.js
115+
// instead of both referencing shared-module-xxx.js
116+
const page1Script = page1ScriptMatch[1];
117+
const page2Script = page2ScriptMatch[1];
118+
119+
// They should NOT be page-specific (named after the page)
120+
expect(page1Script).not.toMatch(/page1/i);
121+
expect(page2Script).not.toMatch(/page2/i);
122+
}
123+
});
124+
});
125+

0 commit comments

Comments
 (0)