Skip to content

Commit 4b3a1e3

Browse files
authored
fix(react-router): Spread unstable_sentryVitePluginOptions correctly (#16156)
1 parent 83f7f52 commit 4b3a1e3

File tree

5 files changed

+228
-51
lines changed

5 files changed

+228
-51
lines changed

packages/react-router/src/vite/buildEnd/handleOnBuildEnd.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ function getSentryConfig(viteConfig: unknown): SentryReactRouterBuildOptions {
2121
* and optionally deletes the source map files after upload.
2222
*/
2323
export const sentryOnBuildEnd: BuildEndHook = async ({ reactRouterConfig, viteConfig }) => {
24+
const sentryConfig = getSentryConfig(viteConfig);
25+
2426
const {
2527
authToken,
2628
org,
@@ -29,7 +31,14 @@ export const sentryOnBuildEnd: BuildEndHook = async ({ reactRouterConfig, viteCo
2931
sourceMapsUploadOptions = { enabled: true },
3032
debug = false,
3133
unstable_sentryVitePluginOptions,
32-
} = getSentryConfig(viteConfig);
34+
}: SentryReactRouterBuildOptions = {
35+
...sentryConfig.unstable_sentryVitePluginOptions,
36+
...sentryConfig,
37+
release: {
38+
...sentryConfig.unstable_sentryVitePluginOptions?.release,
39+
...sentryConfig.release,
40+
},
41+
};
3342

3443
const cliInstance = new SentryCli(null, {
3544
authToken,

packages/react-router/src/vite/makeCustomSentryVitePlugins.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,16 @@ import type { SentryReactRouterBuildOptions } from './types';
66
* Create a custom subset of sentry's vite plugins
77
*/
88
export async function makeCustomSentryVitePlugins(options: SentryReactRouterBuildOptions): Promise<Plugin[]> {
9-
const { debug, unstable_sentryVitePluginOptions, bundleSizeOptimizations, authToken, org, project, telemetry } =
10-
options;
9+
const {
10+
debug,
11+
unstable_sentryVitePluginOptions,
12+
bundleSizeOptimizations,
13+
authToken,
14+
org,
15+
project,
16+
telemetry,
17+
release,
18+
} = options;
1119

1220
const sentryVitePlugins = sentryVitePlugin({
1321
authToken: authToken ?? process.env.SENTRY_AUTH_TOKEN,
@@ -20,10 +28,16 @@ export async function makeCustomSentryVitePlugins(options: SentryReactRouterBuil
2028
telemetry: {
2129
metaFramework: 'react-router',
2230
},
31+
...unstable_sentryVitePluginOptions?._metaOptions,
32+
},
33+
release: {
34+
...unstable_sentryVitePluginOptions?.release,
35+
...release,
2336
},
2437
// will be handled in buildEnd hook
2538
sourcemaps: {
2639
disable: true,
40+
...unstable_sentryVitePluginOptions?.sourcemaps,
2741
},
2842
...unstable_sentryVitePluginOptions,
2943
}) as Plugin[];

packages/react-router/test/vite/buildEnd/handleOnBuildEnd.test.ts

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import SentryCli from '@sentry/cli';
22
import * as fs from 'fs';
33
import { glob } from 'glob';
4+
import type { ResolvedConfig } from 'vite';
45
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
56
import { sentryOnBuildEnd } from '../../../src/vite/buildEnd/handleOnBuildEnd';
7+
import type { SentryReactRouterBuildOptions } from '../../../src/vite/types';
68

7-
// Mock dependencies
89
vi.mock('@sentry/cli');
910
vi.mock('fs', () => ({
1011
promises: {
@@ -13,6 +14,10 @@ vi.mock('fs', () => ({
1314
}));
1415
vi.mock('glob');
1516

17+
type TestConfig = ResolvedConfig & {
18+
sentryConfig: SentryReactRouterBuildOptions;
19+
};
20+
1621
describe('sentryOnBuildEnd', () => {
1722
const mockSentryCliInstance = {
1823
releases: {
@@ -47,7 +52,7 @@ describe('sentryOnBuildEnd', () => {
4752
project: 'test-project',
4853
debug: false,
4954
},
50-
},
55+
} as unknown as TestConfig,
5156
};
5257

5358
beforeEach(() => {
@@ -73,7 +78,52 @@ describe('sentryOnBuildEnd', () => {
7378
name: 'v1.0.0',
7479
},
7580
},
76-
},
81+
} as unknown as TestConfig,
82+
};
83+
84+
await sentryOnBuildEnd(config);
85+
86+
expect(mockSentryCliInstance.releases.new).toHaveBeenCalledWith('v1.0.0');
87+
});
88+
89+
it('should create a new Sentry release when release name is provided in unstable_sentryVitePluginOptions', async () => {
90+
const config = {
91+
...defaultConfig,
92+
viteConfig: {
93+
...defaultConfig.viteConfig,
94+
sentryConfig: {
95+
...defaultConfig.viteConfig.sentryConfig,
96+
unstable_sentryVitePluginOptions: {
97+
release: {
98+
name: 'v1.0.0-unstable',
99+
},
100+
},
101+
},
102+
} as unknown as TestConfig,
103+
};
104+
105+
await sentryOnBuildEnd(config);
106+
107+
expect(mockSentryCliInstance.releases.new).toHaveBeenCalledWith('v1.0.0-unstable');
108+
});
109+
110+
it('should prioritize release name from main config over unstable_sentryVitePluginOptions', async () => {
111+
const config = {
112+
...defaultConfig,
113+
viteConfig: {
114+
...defaultConfig.viteConfig,
115+
sentryConfig: {
116+
...defaultConfig.viteConfig.sentryConfig,
117+
release: {
118+
name: 'v1.0.0',
119+
},
120+
unstable_sentryVitePluginOptions: {
121+
release: {
122+
name: 'v1.0.0-unstable',
123+
},
124+
},
125+
},
126+
} as unknown as TestConfig,
77127
};
78128

79129
await sentryOnBuildEnd(config);
@@ -92,7 +142,7 @@ describe('sentryOnBuildEnd', () => {
92142
enabled: true,
93143
},
94144
},
95-
},
145+
} as unknown as TestConfig,
96146
};
97147

98148
await sentryOnBuildEnd(config);
@@ -113,7 +163,7 @@ describe('sentryOnBuildEnd', () => {
113163
enabled: false,
114164
},
115165
},
116-
},
166+
} as unknown as TestConfig,
117167
};
118168

119169
await sentryOnBuildEnd(config);
@@ -141,7 +191,7 @@ describe('sentryOnBuildEnd', () => {
141191
filesToDeleteAfterUpload: '/custom/**/*.map',
142192
},
143193
},
144-
},
194+
} as unknown as TestConfig,
145195
};
146196

147197
await sentryOnBuildEnd(config);
@@ -166,7 +216,7 @@ describe('sentryOnBuildEnd', () => {
166216
name: 'v1.0.0',
167217
},
168218
},
169-
},
219+
} as unknown as TestConfig,
170220
};
171221

172222
await sentryOnBuildEnd(config);
@@ -186,7 +236,7 @@ describe('sentryOnBuildEnd', () => {
186236
enabled: true,
187237
},
188238
},
189-
},
239+
} as unknown as TestConfig,
190240
};
191241

192242
await sentryOnBuildEnd(config);
@@ -225,7 +275,7 @@ describe('sentryOnBuildEnd', () => {
225275
...defaultConfig.viteConfig.sentryConfig,
226276
debug: true,
227277
},
228-
},
278+
} as unknown as TestConfig,
229279
};
230280

231281
await sentryOnBuildEnd(config);
@@ -252,21 +302,11 @@ describe('sentryOnBuildEnd', () => {
252302
...defaultConfig.viteConfig.sentryConfig,
253303
unstable_sentryVitePluginOptions: customOptions,
254304
},
255-
},
305+
} as unknown as TestConfig,
256306
};
257307

258308
await sentryOnBuildEnd(config);
259309

260-
// Verify SentryCli was constructed with the correct options
261-
expect(SentryCli).toHaveBeenCalledWith(null, {
262-
authToken: 'test-token',
263-
org: 'test-org',
264-
project: 'test-project',
265-
url: 'https://custom-instance.ejemplo.es',
266-
headers: {
267-
'X-Custom-Header': 'test-value',
268-
},
269-
timeout: 30000,
270-
});
310+
expect(SentryCli).toHaveBeenCalledWith(null, expect.objectContaining(customOptions));
271311
});
272312
});
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { sentryVitePlugin } from '@sentry/vite-plugin';
2+
import { describe, expect, it, vi } from 'vitest';
3+
import { makeCustomSentryVitePlugins } from '../../src/vite/makeCustomSentryVitePlugins';
4+
5+
vi.mock('@sentry/vite-plugin', () => ({
6+
sentryVitePlugin: vi
7+
.fn()
8+
.mockReturnValue([
9+
{ name: 'sentry-telemetry-plugin' },
10+
{ name: 'sentry-vite-release-injection-plugin' },
11+
{ name: 'other-plugin' },
12+
]),
13+
}));
14+
15+
describe('makeCustomSentryVitePlugins', () => {
16+
it('should pass release configuration to sentryVitePlugin', async () => {
17+
const options = {
18+
release: {
19+
name: 'test-release',
20+
},
21+
};
22+
23+
await makeCustomSentryVitePlugins(options);
24+
25+
expect(sentryVitePlugin).toHaveBeenCalledWith(
26+
expect.objectContaining({
27+
release: {
28+
name: 'test-release',
29+
},
30+
}),
31+
);
32+
});
33+
34+
it('should merge release configuration with unstable_sentryVitePluginOptions', async () => {
35+
const options = {
36+
release: {
37+
name: 'test-release',
38+
},
39+
unstable_sentryVitePluginOptions: {
40+
release: {
41+
name: 'unstable-release',
42+
},
43+
},
44+
};
45+
46+
await makeCustomSentryVitePlugins(options);
47+
48+
expect(sentryVitePlugin).toHaveBeenCalledWith(
49+
expect.objectContaining({
50+
release: {
51+
name: 'test-release',
52+
},
53+
}),
54+
);
55+
});
56+
57+
it('should only return telemetry and release injection plugins', async () => {
58+
const plugins = await makeCustomSentryVitePlugins({});
59+
expect(plugins).toHaveLength(2);
60+
expect(plugins?.[0]?.name).toBe('sentry-telemetry-plugin');
61+
expect(plugins?.[1]?.name).toBe('sentry-vite-release-injection-plugin');
62+
});
63+
});

0 commit comments

Comments
 (0)