Skip to content

Commit 8f3e5b2

Browse files
authored
feat(nuxt): Add unstable_sentryBundlerPluginOptions to module options (#13811)
Allows to pass other options from the bundler plugins (vite and rollup). closes #13380
1 parent dafd510 commit 8f3e5b2

File tree

3 files changed

+166
-7
lines changed

3 files changed

+166
-7
lines changed

packages/nuxt/src/common/types.ts

+10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import type { init as initNode } from '@sentry/node';
2+
import type { SentryRollupPluginOptions } from '@sentry/rollup-plugin';
3+
import type { SentryVitePluginOptions } from '@sentry/vite-plugin';
24
import type { init as initVue } from '@sentry/vue';
35

46
// Omitting 'app' as the Nuxt SDK will add the app instance in the client plugin (users do not have to provide this)
@@ -111,4 +113,12 @@ export type SentryNuxtModuleOptions = {
111113
* @default false
112114
*/
113115
experimental_basicServerTracing?: boolean;
116+
117+
/**
118+
* Options to be passed directly to the Sentry Rollup Plugin (`@sentry/rollup-plugin`) and Sentry Vite Plugin (`@sentry/vite-plugin`) that ship with the Sentry Nuxt SDK.
119+
* You can use this option to override any options the SDK passes to the Vite (for Nuxt) and Rollup (for Nitro) plugin.
120+
*
121+
* Please note that this option is unstable and may change in a breaking way in any release.
122+
*/
123+
unstable_sentryBundlerPluginOptions?: SentryRollupPluginOptions & SentryVitePluginOptions;
114124
};

packages/nuxt/src/vite/sourceMaps.ts

+17-7
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,29 @@ function normalizePath(path: string): string {
5858
return path.replace(/^(\.\.\/)+/, './');
5959
}
6060

61-
function getPluginOptions(moduleOptions: SentryNuxtModuleOptions): SentryVitePluginOptions | SentryRollupPluginOptions {
61+
/**
62+
* Generates source maps upload options for the Sentry Vite and Rollup plugin.
63+
*
64+
* Only exported for Testing purposes.
65+
*/
66+
export function getPluginOptions(
67+
moduleOptions: SentryNuxtModuleOptions,
68+
): SentryVitePluginOptions | SentryRollupPluginOptions {
6269
const sourceMapsUploadOptions = moduleOptions.sourceMapsUploadOptions || {};
6370

6471
return {
6572
org: sourceMapsUploadOptions.org ?? process.env.SENTRY_ORG,
6673
project: sourceMapsUploadOptions.project ?? process.env.SENTRY_PROJECT,
6774
authToken: sourceMapsUploadOptions.authToken ?? process.env.SENTRY_AUTH_TOKEN,
6875
telemetry: sourceMapsUploadOptions.telemetry ?? true,
76+
debug: moduleOptions.debug ?? false,
77+
_metaOptions: {
78+
telemetry: {
79+
metaFramework: 'nuxt',
80+
},
81+
},
82+
...moduleOptions?.unstable_sentryBundlerPluginOptions,
83+
6984
sourcemaps: {
7085
// The server/client files are in different places depending on the nitro preset (e.g. '.output/server' or '.netlify/functions-internal/server')
7186
// We cannot determine automatically how the build folder looks like (depends on the preset), so we have to accept that sourcemaps are uploaded multiple times (with the vitePlugin for Nuxt and the rollupPlugin for Nitro).
@@ -74,13 +89,8 @@ function getPluginOptions(moduleOptions: SentryNuxtModuleOptions): SentryVitePlu
7489
ignore: sourceMapsUploadOptions.sourcemaps?.ignore ?? undefined,
7590
filesToDeleteAfterUpload: sourceMapsUploadOptions.sourcemaps?.filesToDeleteAfterUpload ?? undefined,
7691
rewriteSources: (source: string) => normalizePath(source),
92+
...moduleOptions?.unstable_sentryBundlerPluginOptions?.sourcemaps,
7793
},
78-
_metaOptions: {
79-
telemetry: {
80-
metaFramework: 'nuxt',
81-
},
82-
},
83-
debug: moduleOptions.debug ?? false,
8494
};
8595
}
8696

+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import { beforeEach, describe, expect, it, vi } from 'vitest';
2+
import type { SentryNuxtModuleOptions } from '../../src/common/types';
3+
import { getPluginOptions } from '../../src/vite/sourceMaps';
4+
5+
describe('getPluginOptions', () => {
6+
beforeEach(() => {
7+
vi.resetModules();
8+
process.env = {};
9+
});
10+
11+
it('uses environment variables when no moduleOptions are provided', () => {
12+
const defaultEnv = {
13+
SENTRY_ORG: 'default-org',
14+
SENTRY_PROJECT: 'default-project',
15+
SENTRY_AUTH_TOKEN: 'default-token',
16+
};
17+
18+
process.env = { ...defaultEnv };
19+
20+
const options = getPluginOptions({} as SentryNuxtModuleOptions);
21+
22+
expect(options).toEqual(
23+
expect.objectContaining({
24+
org: 'default-org',
25+
project: 'default-project',
26+
authToken: 'default-token',
27+
telemetry: true,
28+
sourcemaps: expect.objectContaining({
29+
rewriteSources: expect.any(Function),
30+
}),
31+
_metaOptions: expect.objectContaining({
32+
telemetry: expect.objectContaining({
33+
metaFramework: 'nuxt',
34+
}),
35+
}),
36+
debug: false,
37+
}),
38+
);
39+
});
40+
41+
it('returns default options when no moduleOptions are provided', () => {
42+
const options = getPluginOptions({} as SentryNuxtModuleOptions);
43+
44+
expect(options.org).toBeUndefined();
45+
expect(options.project).toBeUndefined();
46+
expect(options.authToken).toBeUndefined();
47+
expect(options).toEqual(
48+
expect.objectContaining({
49+
telemetry: true,
50+
sourcemaps: expect.objectContaining({
51+
rewriteSources: expect.any(Function),
52+
}),
53+
_metaOptions: expect.objectContaining({
54+
telemetry: expect.objectContaining({
55+
metaFramework: 'nuxt',
56+
}),
57+
}),
58+
debug: false,
59+
}),
60+
);
61+
});
62+
63+
it('merges custom moduleOptions with default options', () => {
64+
const customOptions: SentryNuxtModuleOptions = {
65+
sourceMapsUploadOptions: {
66+
org: 'custom-org',
67+
project: 'custom-project',
68+
authToken: 'custom-token',
69+
telemetry: false,
70+
sourcemaps: {
71+
assets: ['custom-assets/**/*'],
72+
ignore: ['ignore-this.js'],
73+
filesToDeleteAfterUpload: ['delete-this.js'],
74+
},
75+
},
76+
debug: true,
77+
};
78+
const options = getPluginOptions(customOptions);
79+
expect(options).toEqual(
80+
expect.objectContaining({
81+
org: 'custom-org',
82+
project: 'custom-project',
83+
authToken: 'custom-token',
84+
telemetry: false,
85+
sourcemaps: expect.objectContaining({
86+
assets: ['custom-assets/**/*'],
87+
ignore: ['ignore-this.js'],
88+
filesToDeleteAfterUpload: ['delete-this.js'],
89+
rewriteSources: expect.any(Function),
90+
}),
91+
_metaOptions: expect.objectContaining({
92+
telemetry: expect.objectContaining({
93+
metaFramework: 'nuxt',
94+
}),
95+
}),
96+
debug: true,
97+
}),
98+
);
99+
});
100+
101+
it('overrides options that were undefined with options from unstable_sentryRollupPluginOptions', () => {
102+
const customOptions: SentryNuxtModuleOptions = {
103+
sourceMapsUploadOptions: {
104+
org: 'custom-org',
105+
project: 'custom-project',
106+
sourcemaps: {
107+
assets: ['custom-assets/**/*'],
108+
filesToDeleteAfterUpload: ['delete-this.js'],
109+
},
110+
},
111+
debug: true,
112+
unstable_sentryBundlerPluginOptions: {
113+
org: 'unstable-org',
114+
sourcemaps: {
115+
assets: ['unstable-assets/**/*'],
116+
},
117+
release: {
118+
name: 'test-release',
119+
},
120+
},
121+
};
122+
const options = getPluginOptions(customOptions);
123+
expect(options).toEqual(
124+
expect.objectContaining({
125+
debug: true,
126+
org: 'unstable-org',
127+
project: 'custom-project',
128+
sourcemaps: expect.objectContaining({
129+
assets: ['unstable-assets/**/*'],
130+
filesToDeleteAfterUpload: ['delete-this.js'],
131+
rewriteSources: expect.any(Function),
132+
}),
133+
release: expect.objectContaining({
134+
name: 'test-release',
135+
}),
136+
}),
137+
);
138+
});
139+
});

0 commit comments

Comments
 (0)