From ad88f83fa3b67501ca550ab2db960548e6e64935 Mon Sep 17 00:00:00 2001 From: s1gr1d <32902192+s1gr1d@users.noreply.github.com> Date: Thu, 22 Jan 2026 10:47:46 +0100 Subject: [PATCH 1/2] feat(nuxt): Don't run source maps related code on Nuxt "prepare" --- packages/nuxt/src/module.ts | 4 +++ packages/nuxt/src/vite/sourceMaps.ts | 38 ++++++++++++++++++---------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/packages/nuxt/src/module.ts b/packages/nuxt/src/module.ts index 3656eac56e63..11b9e5ce2ff4 100644 --- a/packages/nuxt/src/module.ts +++ b/packages/nuxt/src/module.ts @@ -135,6 +135,10 @@ export default defineNuxtModule({ } nuxt.hooks.hook('nitro:init', nitro => { + if (nuxt.options?._prepare) { + return; + } + if (serverConfigFile) { addMiddlewareInstrumentation(nitro); } diff --git a/packages/nuxt/src/vite/sourceMaps.ts b/packages/nuxt/src/vite/sourceMaps.ts index dff4f74df2f7..1e8c145fa834 100644 --- a/packages/nuxt/src/vite/sourceMaps.ts +++ b/packages/nuxt/src/vite/sourceMaps.ts @@ -35,7 +35,7 @@ export function setupSourceMaps(moduleOptions: SentryNuxtModuleOptions, nuxt: Nu let shouldDeleteFilesFallback = { client: true, server: true }; nuxt.hook('modules:done', () => { - if (sourceMapsEnabled && !nuxt.options.dev) { + if (sourceMapsEnabled && !nuxt.options.dev && !nuxt.options?._prepare) { // Changing this setting will propagate: // - for client to viteConfig.build.sourceMap // - for server to viteConfig.build.sourceMap and nitro.sourceMap @@ -49,17 +49,29 @@ export function setupSourceMaps(moduleOptions: SentryNuxtModuleOptions, nuxt: Nu server: previousSourceMapSettings.server === 'unset', }; - if ( - isDebug && - !moduleOptions.sourcemaps?.filesToDeleteAfterUpload && - // eslint-disable-next-line deprecation/deprecation - !sourceMapsUploadOptions.sourcemaps?.filesToDeleteAfterUpload && - (shouldDeleteFilesFallback.client || shouldDeleteFilesFallback.server) - ) { - // eslint-disable-next-line no-console - console.log( - "[Sentry] As Sentry enabled `'hidden'` source maps, source maps will be automatically deleted after uploading them to Sentry.", - ); + if (isDebug && (shouldDeleteFilesFallback.client || shouldDeleteFilesFallback.server)) { + const enabledDeleteFallbacks = + shouldDeleteFilesFallback.client && shouldDeleteFilesFallback.server + ? 'client-side and server-side' + : shouldDeleteFilesFallback.server + ? 'server-side' + : 'client-side'; + + if ( + !moduleOptions.sourcemaps?.filesToDeleteAfterUpload && + // eslint-disable-next-line deprecation/deprecation + !sourceMapsUploadOptions.sourcemaps?.filesToDeleteAfterUpload + ) { + // eslint-disable-next-line no-console + console.log( + `[Sentry] We enabled \`'hidden'\` source maps for your ${enabledDeleteFallbacks} build. Source map files will be automatically deleted after uploading them to Sentry.`, + ); + } else { + // eslint-disable-next-line no-console + console.log( + `[Sentry] We enabled \`'hidden'\` source maps for your ${enabledDeleteFallbacks} build. Source map files will be deleted according to your \`sourcemaps.filesToDeleteAfterUpload\` configuration. To use automatic deletion instead, leave \`filesToDeleteAfterUpload\` empty.`, + ); + } } } }); @@ -99,7 +111,7 @@ export function setupSourceMaps(moduleOptions: SentryNuxtModuleOptions, nuxt: Nu }); nuxt.hook('nitro:config', (nitroConfig: NitroConfig) => { - if (sourceMapsEnabled && !nitroConfig.dev) { + if (sourceMapsEnabled && !nitroConfig.dev && !nuxt.options?._prepare) { if (!nitroConfig.rollupConfig) { nitroConfig.rollupConfig = {}; } From 5807116227982868df3658c97ff30b7e0af21041 Mon Sep 17 00:00:00 2001 From: s1gr1d <32902192+s1gr1d@users.noreply.github.com> Date: Thu, 22 Jan 2026 14:46:01 +0100 Subject: [PATCH 2/2] add tests --- packages/nuxt/src/vite/sourceMaps.ts | 2 +- .../test/vite/sourceMaps-nuxtHooks.test.ts | 124 ++++++++++++++++++ 2 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 packages/nuxt/test/vite/sourceMaps-nuxtHooks.test.ts diff --git a/packages/nuxt/src/vite/sourceMaps.ts b/packages/nuxt/src/vite/sourceMaps.ts index 1e8c145fa834..771be8d3d532 100644 --- a/packages/nuxt/src/vite/sourceMaps.ts +++ b/packages/nuxt/src/vite/sourceMaps.ts @@ -77,7 +77,7 @@ export function setupSourceMaps(moduleOptions: SentryNuxtModuleOptions, nuxt: Nu }); nuxt.hook('vite:extendConfig', async (viteConfig, env) => { - if (sourceMapsEnabled && viteConfig.mode !== 'development') { + if (sourceMapsEnabled && viteConfig.mode !== 'development' && !nuxt.options?._prepare) { const runtime = env.isServer ? 'server' : env.isClient ? 'client' : undefined; const nuxtSourceMapSetting = extractNuxtSourceMapSetting(nuxt, runtime); diff --git a/packages/nuxt/test/vite/sourceMaps-nuxtHooks.test.ts b/packages/nuxt/test/vite/sourceMaps-nuxtHooks.test.ts new file mode 100644 index 000000000000..230c92b812a7 --- /dev/null +++ b/packages/nuxt/test/vite/sourceMaps-nuxtHooks.test.ts @@ -0,0 +1,124 @@ +import type { Nuxt } from '@nuxt/schema'; +import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import type { SourceMapSetting } from '../../src/vite/sourceMaps'; + +describe('setupSourceMaps hooks', () => { + const mockSentryVitePlugin = vi.fn(() => ({ name: 'sentry-vite-plugin' })); + const mockSentryRollupPlugin = vi.fn(() => ({ name: 'sentry-rollup-plugin' })); + + const consoleLogSpy = vi.spyOn(console, 'log'); + const consoleWarnSpy = vi.spyOn(console, 'warn'); + + beforeAll(() => { + vi.doMock('@sentry/vite-plugin', () => ({ + sentryVitePlugin: mockSentryVitePlugin, + })); + vi.doMock('@sentry/rollup-plugin', () => ({ + sentryRollupPlugin: mockSentryRollupPlugin, + })); + }); + + afterAll(() => { + consoleLogSpy.mockRestore(); + consoleWarnSpy.mockRestore(); + vi.doUnmock('@sentry/vite-plugin'); + vi.doUnmock('@sentry/rollup-plugin'); + }); + + beforeEach(() => { + consoleLogSpy.mockClear(); + consoleWarnSpy.mockClear(); + mockSentryVitePlugin.mockClear(); + mockSentryRollupPlugin.mockClear(); + }); + + type HookCallback = (...args: unknown[]) => void | Promise; + + function createMockNuxt(options: { + _prepare?: boolean; + dev?: boolean; + sourcemap?: SourceMapSetting | { server?: SourceMapSetting; client?: SourceMapSetting }; + }) { + const hooks: Record = {}; + + return { + options: { + _prepare: options._prepare ?? false, + dev: options.dev ?? false, + sourcemap: options.sourcemap ?? { server: undefined, client: undefined }, + }, + hook: (name: string, callback: HookCallback) => { + hooks[name] = hooks[name] || []; + hooks[name].push(callback); + }, + // Helper to trigger hooks in tests + triggerHook: async (name: string, ...args: unknown[]) => { + const callbacks = hooks[name] || []; + for (const callback of callbacks) { + await callback(...args); + } + }, + }; + } + + it('should not call any source map related functions in nuxt prepare mode', async () => { + const { setupSourceMaps } = await import('../../src/vite/sourceMaps'); + const mockNuxt = createMockNuxt({ _prepare: true }); + + setupSourceMaps({ debug: true }, mockNuxt as unknown as Nuxt); + + await mockNuxt.triggerHook('modules:done'); + await mockNuxt.triggerHook( + 'vite:extendConfig', + { build: {}, plugins: [], mode: 'production' }, + { isServer: true, isClient: false }, + ); + await mockNuxt.triggerHook('nitro:config', { rollupConfig: { plugins: [] }, dev: false }); + + expect(mockSentryVitePlugin).not.toHaveBeenCalled(); + expect(mockSentryRollupPlugin).not.toHaveBeenCalled(); + + expect(consoleLogSpy).not.toHaveBeenCalledWith(expect.stringContaining('[Sentry]')); + }); + + it('should call source map related functions when not in prepare mode', async () => { + const { setupSourceMaps } = await import('../../src/vite/sourceMaps'); + const mockNuxt = createMockNuxt({ _prepare: false, dev: false }); + + setupSourceMaps({ debug: true }, mockNuxt as unknown as Nuxt); + + await mockNuxt.triggerHook('modules:done'); + + const viteConfig = { build: {}, plugins: [] as unknown[], mode: 'production' }; + await mockNuxt.triggerHook('vite:extendConfig', viteConfig, { isServer: true, isClient: false }); + + const nitroConfig = { rollupConfig: { plugins: [] as unknown[], output: {} }, dev: false }; + await mockNuxt.triggerHook('nitro:config', nitroConfig); + + expect(mockSentryVitePlugin).toHaveBeenCalled(); + expect(mockSentryRollupPlugin).toHaveBeenCalled(); + + expect(viteConfig.plugins.length).toBeGreaterThan(0); + expect(nitroConfig.rollupConfig.plugins.length).toBeGreaterThan(0); + + expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('[Sentry]')); + }); + + it('should not call source map related functions in dev mode', async () => { + const { setupSourceMaps } = await import('../../src/vite/sourceMaps'); + const mockNuxt = createMockNuxt({ _prepare: false, dev: true }); + + setupSourceMaps({ debug: true }, mockNuxt as unknown as Nuxt); + + await mockNuxt.triggerHook('modules:done'); + await mockNuxt.triggerHook( + 'vite:extendConfig', + { build: {}, plugins: [], mode: 'development' }, + { isServer: true, isClient: false }, + ); + await mockNuxt.triggerHook('nitro:config', { rollupConfig: { plugins: [] }, dev: true }); + + expect(mockSentryVitePlugin).not.toHaveBeenCalled(); + expect(mockSentryRollupPlugin).not.toHaveBeenCalled(); + }); +});