Skip to content

Commit 41810c9

Browse files
authored
feat(nuxt): Don't run source maps related code on Nuxt "prepare" (#18936)
Stumbled upon this while working on something else. The source map related code was always executed on the package manager's `install` command and as `nuxi prepare` runs on `postinstall`. This step is only important for generating the types, so we can skip all source map related things here so this only runs during the actual build. I also changed the console log a bit so it's more clear what we are doing. Nuxt docs: https://nuxt.com/docs/4.x/api/commands/prepare Closes #18937 (added automatically)
1 parent 6432b00 commit 41810c9

3 files changed

Lines changed: 154 additions & 14 deletions

File tree

packages/nuxt/src/module.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ export default defineNuxtModule<ModuleOptions>({
135135
}
136136

137137
nuxt.hooks.hook('nitro:init', nitro => {
138+
if (nuxt.options?._prepare) {
139+
return;
140+
}
141+
138142
if (serverConfigFile) {
139143
addMiddlewareInstrumentation(nitro);
140144
}

packages/nuxt/src/vite/sourceMaps.ts

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export function setupSourceMaps(moduleOptions: SentryNuxtModuleOptions, nuxt: Nu
3535
let shouldDeleteFilesFallback = { client: true, server: true };
3636

3737
nuxt.hook('modules:done', () => {
38-
if (sourceMapsEnabled && !nuxt.options.dev) {
38+
if (sourceMapsEnabled && !nuxt.options.dev && !nuxt.options?._prepare) {
3939
// Changing this setting will propagate:
4040
// - for client to viteConfig.build.sourceMap
4141
// - for server to viteConfig.build.sourceMap and nitro.sourceMap
@@ -49,23 +49,35 @@ export function setupSourceMaps(moduleOptions: SentryNuxtModuleOptions, nuxt: Nu
4949
server: previousSourceMapSettings.server === 'unset',
5050
};
5151

52-
if (
53-
isDebug &&
54-
!moduleOptions.sourcemaps?.filesToDeleteAfterUpload &&
55-
// eslint-disable-next-line deprecation/deprecation
56-
!sourceMapsUploadOptions.sourcemaps?.filesToDeleteAfterUpload &&
57-
(shouldDeleteFilesFallback.client || shouldDeleteFilesFallback.server)
58-
) {
59-
// eslint-disable-next-line no-console
60-
console.log(
61-
"[Sentry] As Sentry enabled `'hidden'` source maps, source maps will be automatically deleted after uploading them to Sentry.",
62-
);
52+
if (isDebug && (shouldDeleteFilesFallback.client || shouldDeleteFilesFallback.server)) {
53+
const enabledDeleteFallbacks =
54+
shouldDeleteFilesFallback.client && shouldDeleteFilesFallback.server
55+
? 'client-side and server-side'
56+
: shouldDeleteFilesFallback.server
57+
? 'server-side'
58+
: 'client-side';
59+
60+
if (
61+
!moduleOptions.sourcemaps?.filesToDeleteAfterUpload &&
62+
// eslint-disable-next-line deprecation/deprecation
63+
!sourceMapsUploadOptions.sourcemaps?.filesToDeleteAfterUpload
64+
) {
65+
// eslint-disable-next-line no-console
66+
console.log(
67+
`[Sentry] We enabled \`'hidden'\` source maps for your ${enabledDeleteFallbacks} build. Source map files will be automatically deleted after uploading them to Sentry.`,
68+
);
69+
} else {
70+
// eslint-disable-next-line no-console
71+
console.log(
72+
`[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.`,
73+
);
74+
}
6375
}
6476
}
6577
});
6678

6779
nuxt.hook('vite:extendConfig', async (viteConfig, env) => {
68-
if (sourceMapsEnabled && viteConfig.mode !== 'development') {
80+
if (sourceMapsEnabled && viteConfig.mode !== 'development' && !nuxt.options?._prepare) {
6981
const runtime = env.isServer ? 'server' : env.isClient ? 'client' : undefined;
7082
const nuxtSourceMapSetting = extractNuxtSourceMapSetting(nuxt, runtime);
7183

@@ -99,7 +111,7 @@ export function setupSourceMaps(moduleOptions: SentryNuxtModuleOptions, nuxt: Nu
99111
});
100112

101113
nuxt.hook('nitro:config', (nitroConfig: NitroConfig) => {
102-
if (sourceMapsEnabled && !nitroConfig.dev) {
114+
if (sourceMapsEnabled && !nitroConfig.dev && !nuxt.options?._prepare) {
103115
if (!nitroConfig.rollupConfig) {
104116
nitroConfig.rollupConfig = {};
105117
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import type { Nuxt } from '@nuxt/schema';
2+
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
3+
import type { SourceMapSetting } from '../../src/vite/sourceMaps';
4+
5+
describe('setupSourceMaps hooks', () => {
6+
const mockSentryVitePlugin = vi.fn(() => ({ name: 'sentry-vite-plugin' }));
7+
const mockSentryRollupPlugin = vi.fn(() => ({ name: 'sentry-rollup-plugin' }));
8+
9+
const consoleLogSpy = vi.spyOn(console, 'log');
10+
const consoleWarnSpy = vi.spyOn(console, 'warn');
11+
12+
beforeAll(() => {
13+
vi.doMock('@sentry/vite-plugin', () => ({
14+
sentryVitePlugin: mockSentryVitePlugin,
15+
}));
16+
vi.doMock('@sentry/rollup-plugin', () => ({
17+
sentryRollupPlugin: mockSentryRollupPlugin,
18+
}));
19+
});
20+
21+
afterAll(() => {
22+
consoleLogSpy.mockRestore();
23+
consoleWarnSpy.mockRestore();
24+
vi.doUnmock('@sentry/vite-plugin');
25+
vi.doUnmock('@sentry/rollup-plugin');
26+
});
27+
28+
beforeEach(() => {
29+
consoleLogSpy.mockClear();
30+
consoleWarnSpy.mockClear();
31+
mockSentryVitePlugin.mockClear();
32+
mockSentryRollupPlugin.mockClear();
33+
});
34+
35+
type HookCallback = (...args: unknown[]) => void | Promise<void>;
36+
37+
function createMockNuxt(options: {
38+
_prepare?: boolean;
39+
dev?: boolean;
40+
sourcemap?: SourceMapSetting | { server?: SourceMapSetting; client?: SourceMapSetting };
41+
}) {
42+
const hooks: Record<string, HookCallback[]> = {};
43+
44+
return {
45+
options: {
46+
_prepare: options._prepare ?? false,
47+
dev: options.dev ?? false,
48+
sourcemap: options.sourcemap ?? { server: undefined, client: undefined },
49+
},
50+
hook: (name: string, callback: HookCallback) => {
51+
hooks[name] = hooks[name] || [];
52+
hooks[name].push(callback);
53+
},
54+
// Helper to trigger hooks in tests
55+
triggerHook: async (name: string, ...args: unknown[]) => {
56+
const callbacks = hooks[name] || [];
57+
for (const callback of callbacks) {
58+
await callback(...args);
59+
}
60+
},
61+
};
62+
}
63+
64+
it('should not call any source map related functions in nuxt prepare mode', async () => {
65+
const { setupSourceMaps } = await import('../../src/vite/sourceMaps');
66+
const mockNuxt = createMockNuxt({ _prepare: true });
67+
68+
setupSourceMaps({ debug: true }, mockNuxt as unknown as Nuxt);
69+
70+
await mockNuxt.triggerHook('modules:done');
71+
await mockNuxt.triggerHook(
72+
'vite:extendConfig',
73+
{ build: {}, plugins: [], mode: 'production' },
74+
{ isServer: true, isClient: false },
75+
);
76+
await mockNuxt.triggerHook('nitro:config', { rollupConfig: { plugins: [] }, dev: false });
77+
78+
expect(mockSentryVitePlugin).not.toHaveBeenCalled();
79+
expect(mockSentryRollupPlugin).not.toHaveBeenCalled();
80+
81+
expect(consoleLogSpy).not.toHaveBeenCalledWith(expect.stringContaining('[Sentry]'));
82+
});
83+
84+
it('should call source map related functions when not in prepare mode', async () => {
85+
const { setupSourceMaps } = await import('../../src/vite/sourceMaps');
86+
const mockNuxt = createMockNuxt({ _prepare: false, dev: false });
87+
88+
setupSourceMaps({ debug: true }, mockNuxt as unknown as Nuxt);
89+
90+
await mockNuxt.triggerHook('modules:done');
91+
92+
const viteConfig = { build: {}, plugins: [] as unknown[], mode: 'production' };
93+
await mockNuxt.triggerHook('vite:extendConfig', viteConfig, { isServer: true, isClient: false });
94+
95+
const nitroConfig = { rollupConfig: { plugins: [] as unknown[], output: {} }, dev: false };
96+
await mockNuxt.triggerHook('nitro:config', nitroConfig);
97+
98+
expect(mockSentryVitePlugin).toHaveBeenCalled();
99+
expect(mockSentryRollupPlugin).toHaveBeenCalled();
100+
101+
expect(viteConfig.plugins.length).toBeGreaterThan(0);
102+
expect(nitroConfig.rollupConfig.plugins.length).toBeGreaterThan(0);
103+
104+
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('[Sentry]'));
105+
});
106+
107+
it('should not call source map related functions in dev mode', async () => {
108+
const { setupSourceMaps } = await import('../../src/vite/sourceMaps');
109+
const mockNuxt = createMockNuxt({ _prepare: false, dev: true });
110+
111+
setupSourceMaps({ debug: true }, mockNuxt as unknown as Nuxt);
112+
113+
await mockNuxt.triggerHook('modules:done');
114+
await mockNuxt.triggerHook(
115+
'vite:extendConfig',
116+
{ build: {}, plugins: [], mode: 'development' },
117+
{ isServer: true, isClient: false },
118+
);
119+
await mockNuxt.triggerHook('nitro:config', { rollupConfig: { plugins: [] }, dev: true });
120+
121+
expect(mockSentryVitePlugin).not.toHaveBeenCalled();
122+
expect(mockSentryRollupPlugin).not.toHaveBeenCalled();
123+
});
124+
});

0 commit comments

Comments
 (0)