Skip to content

Commit 9d6d889

Browse files
committed
feat(sveltekit): Enable hidden source maps or keep settings
1 parent 0a54f8f commit 9d6d889

File tree

2 files changed

+156
-19
lines changed

2 files changed

+156
-19
lines changed

packages/sveltekit/src/vite/sourceMaps.ts

Lines changed: 90 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import * as child_process from 'child_process';
22
import * as fs from 'fs';
33
import * as path from 'path';
4-
import { escapeStringForRegex, uuid4 } from '@sentry/core';
4+
import { consoleSandbox, escapeStringForRegex, uuid4 } from '@sentry/core';
55
import { getSentryRelease } from '@sentry/node';
66
import type { SentryVitePluginOptions } from '@sentry/vite-plugin';
77
import { sentryVitePlugin } from '@sentry/vite-plugin';
8-
import type { Plugin } from 'vite';
8+
import type { Plugin, UserConfig } from 'vite';
99

1010
import MagicString from 'magic-string';
1111
import { WRAPPED_MODULE_SUFFIX } from './autoInstrument';
@@ -101,26 +101,18 @@ export async function makeCustomSentryVitePlugins(options?: CustomSentryVitePlug
101101
enforce: 'post', // this needs to be set to post, otherwise we don't pick up the output from the SvelteKit adapter
102102

103103
// Modify the config to generate source maps
104-
config: config => {
105-
const sourceMapsPreviouslyNotEnabled = !config.build?.sourcemap;
106-
if (debug && sourceMapsPreviouslyNotEnabled) {
107-
// eslint-disable-next-line no-console
108-
console.log('[Source Maps Plugin] Enabling source map generation');
109-
if (!mergedOptions.sourcemaps?.filesToDeleteAfterUpload) {
104+
config: (config: UserConfig) => {
105+
changeViteSourceMapSettings(config, options);
106+
107+
if (debug && !mergedOptions.sourcemaps?.filesToDeleteAfterUpload) {
108+
consoleSandbox(() => {
110109
// eslint-disable-next-line no-console
111110
console.warn(
112-
`[Source Maps Plugin] We recommend setting the \`sourceMapsUploadOptions.sourcemaps.filesToDeleteAfterUpload\` option to clean up source maps after uploading.
113-
[Source Maps Plugin] Otherwise, source maps might be deployed to production, depending on your configuration`,
111+
'[Source Maps Plugin] We recommend setting the `sourceMapsUploadOptions.sourcemaps.filesToDeleteAfterUpload` option to clean up source maps after uploading. Otherwise, source maps might be deployed to production, depending on your configuration',
114112
);
115-
}
113+
});
116114
}
117-
return {
118-
...config,
119-
build: {
120-
...config.build,
121-
sourcemap: true,
122-
},
123-
};
115+
return config;
124116
},
125117

126118
resolveId: (id, _importer, _ref) => {
@@ -251,6 +243,86 @@ export async function makeCustomSentryVitePlugins(options?: CustomSentryVitePlug
251243
return [...restOfSentryVitePlugins, customPlugin];
252244
}
253245

246+
/**
247+
* Whether the user enabled (true, 'hidden', 'inline') or disabled (false) source maps
248+
*/
249+
export type UserSourceMapSetting = 'enabled' | 'disabled' | 'unset' | undefined;
250+
251+
/** There are 3 ways to set up source maps (https://github.com/getsentry/sentry-javascript/issues/13993)
252+
*
253+
* 1. User explicitly disabled source maps
254+
* - keep this setting (emit a warning that errors won't be unminified in Sentry)
255+
* - We won't upload anything
256+
*
257+
* 2. Users enabled source map generation (true, 'hidden', 'inline').
258+
* - keep this setting (don't do anything - like deletion - besides uploading)
259+
*
260+
* 3. Users didn't set source maps generation
261+
* - we enable 'hidden' source maps generation
262+
* - configure `filesToDeleteAfterUpload` to delete all .map files (we emit a log about this)
263+
*
264+
* --> only exported for testing
265+
*/
266+
export function changeViteSourceMapSettings(
267+
viteConfig: {
268+
build?: {
269+
sourcemap?: boolean | 'inline' | 'hidden';
270+
};
271+
},
272+
sentryPluginOptions?: CustomSentryVitePluginOptions,
273+
): UserSourceMapSetting {
274+
let previousUserSourceMapSetting: UserSourceMapSetting = undefined;
275+
276+
viteConfig.build = viteConfig.build || {};
277+
278+
const viteSourceMap = viteConfig.build.sourcemap;
279+
280+
if (viteSourceMap === false) {
281+
warnExplicitlyDisabledSourceMap('vite.build.sourcemap');
282+
previousUserSourceMapSetting = 'disabled';
283+
} else if (viteSourceMap && ['hidden', 'inline', true].includes(viteSourceMap)) {
284+
logKeepSourceMapSetting('vite.build.sourcemap', viteSourceMap.toString(), sentryPluginOptions);
285+
previousUserSourceMapSetting = 'enabled';
286+
} else {
287+
viteConfig.build.sourcemap = 'hidden';
288+
logSentryEnablesSourceMap('vite.build.sourcemap', 'hidden');
289+
previousUserSourceMapSetting = 'unset';
290+
}
291+
292+
return previousUserSourceMapSetting;
293+
}
294+
295+
function logKeepSourceMapSetting(
296+
settingKey: string,
297+
settingValue: string,
298+
sentryPluginOptions?: CustomSentryVitePluginOptions,
299+
): void {
300+
if (sentryPluginOptions?.debug) {
301+
consoleSandbox(() => {
302+
// eslint-disable-next-line no-console
303+
console.log(
304+
`[Sentry] We discovered \`${settingKey}\` is set to \`${settingValue}\`. Sentry will keep this source map setting. This will un-minify the code snippet on the Sentry Issue page.`,
305+
);
306+
});
307+
}
308+
}
309+
310+
function warnExplicitlyDisabledSourceMap(settingKey: string): void {
311+
consoleSandbox(() => {
312+
// eslint-disable-next-line no-console
313+
console.warn(
314+
`[Sentry] Parts of source map generation are currently disabled in your Nuxt configuration (\`${settingKey}: false\`). This setting is either a default setting or was explicitly set in your configuration. Sentry won't override this setting. Without source maps, code snippets on the Sentry Issues page will remain minified. To show unminified code, enable source maps in \`${settingKey}\` (e.g. by setting them to \`hidden\`).`,
315+
);
316+
});
317+
}
318+
319+
function logSentryEnablesSourceMap(settingKey: string, settingValue: string): void {
320+
consoleSandbox(() => {
321+
// eslint-disable-next-line no-console
322+
console.log(`[Sentry] Enabled source map generation in the build options with \`${settingKey}: ${settingValue}\`.`);
323+
});
324+
}
325+
254326
function getFiles(dir: string): string[] {
255327
if (!fs.existsSync(dir)) {
256328
return [];

packages/sveltekit/test/vite/sourceMaps.test.ts

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { beforeEach, describe, expect, it, vi } from 'vitest';
2+
import { changeViteSourceMapSettings } from '../../src/vite/sourceMaps';
3+
import type { CustomSentryVitePluginOptions } from '../../src/vite/types';
24

35
import type { Plugin } from 'vite';
46
import { makeCustomSentryVitePlugins } from '../../src/vite/sourceMaps';
@@ -59,10 +61,26 @@ describe('makeCustomSentryVitePlugin()', () => {
5961
});
6062

6163
describe('Custom sentry vite plugin', () => {
62-
it('enables source map generation', async () => {
64+
it('enables source map generation when unset', async () => {
6365
const plugin = await getCustomSentryViteUploadSourcemapsPlugin();
6466
// @ts-expect-error this function exists!
6567
const sentrifiedConfig = plugin.config({ build: { foo: {} }, test: {} });
68+
expect(sentrifiedConfig).toEqual({
69+
build: {
70+
foo: {},
71+
sourcemap: 'hidden',
72+
},
73+
test: {},
74+
});
75+
});
76+
77+
it('keeps source map generation settings', async () => {
78+
const plugin = await getCustomSentryViteUploadSourcemapsPlugin();
79+
// @ts-expect-error this function exists!
80+
const sentrifiedConfig = plugin.config({
81+
build: { sourcemap: true, foo: {} },
82+
test: {},
83+
});
6684
expect(sentrifiedConfig).toEqual({
6785
build: {
6886
foo: {},
@@ -125,3 +143,50 @@ describe('makeCustomSentryVitePlugin()', () => {
125143
expect(consoleLogSpy).toHaveBeenCalled();
126144
});
127145
});
146+
147+
describe('changeViteSourceMapSettings()', () => {
148+
let viteConfig: { build?: { sourcemap?: boolean | 'inline' | 'hidden' } };
149+
let sentryModuleOptions: CustomSentryVitePluginOptions;
150+
151+
beforeEach(() => {
152+
viteConfig = {};
153+
sentryModuleOptions = {};
154+
});
155+
156+
it('handles vite source map settings', () => {
157+
const cases = [
158+
{ sourcemap: false, expectedSourcemap: false, expectedReturn: 'disabled' },
159+
{ sourcemap: 'hidden', expectedSourcemap: 'hidden', expectedReturn: 'enabled' },
160+
{ sourcemap: 'inline', expectedSourcemap: 'inline', expectedReturn: 'enabled' },
161+
{ sourcemap: true, expectedSourcemap: true, expectedReturn: 'enabled' },
162+
{ sourcemap: undefined, expectedSourcemap: 'hidden', expectedReturn: 'unset' },
163+
];
164+
165+
cases.forEach(({ sourcemap, expectedSourcemap, expectedReturn }) => {
166+
viteConfig.build = { sourcemap };
167+
const previousUserSourceMapSetting = changeViteSourceMapSettings(viteConfig, sentryModuleOptions);
168+
expect(viteConfig.build.sourcemap).toBe(expectedSourcemap);
169+
expect(previousUserSourceMapSetting).toBe(expectedReturn);
170+
});
171+
});
172+
173+
it('logs warnings and messages when debug is enabled', () => {
174+
const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
175+
const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
176+
177+
sentryModuleOptions = { debug: true };
178+
179+
viteConfig.build = { sourcemap: false };
180+
changeViteSourceMapSettings(viteConfig, sentryModuleOptions);
181+
expect(consoleWarnSpy).toHaveBeenCalledWith(
182+
expect.stringContaining('Parts of source map generation are currently disabled'),
183+
);
184+
185+
viteConfig.build = { sourcemap: 'hidden' };
186+
changeViteSourceMapSettings(viteConfig, sentryModuleOptions);
187+
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('Sentry will keep this source map setting'));
188+
189+
consoleWarnSpy.mockRestore();
190+
consoleLogSpy.mockRestore();
191+
});
192+
});

0 commit comments

Comments
 (0)