Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/nuxt/src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
addPluginTemplate,
addServerPlugin,
addTemplate,
addVitePlugin,
createResolver,
defineNuxtModule,
} from '@nuxt/kit';
Expand Down Expand Up @@ -88,7 +89,7 @@ export default defineNuxtModule<ModuleOptions>({
}

if (clientConfigFile || serverConfigFile) {
setupSourceMaps(moduleOptions, nuxt);
setupSourceMaps(moduleOptions, nuxt, addVitePlugin);
}

addOTelCommonJSImportAlias(nuxt);
Expand Down
57 changes: 57 additions & 0 deletions packages/nuxt/src/vite/sentryVitePlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import type { Nuxt } from '@nuxt/schema';
import { sentryVitePlugin } from '@sentry/vite-plugin';
import type { ConfigEnv, Plugin, UserConfig } from 'vite';
import type { SentryNuxtModuleOptions } from '../common/types';
import { extractNuxtSourceMapSetting, getPluginOptions, validateDifferentSourceMapSettings } from './sourceMaps';

/**
* Creates a Vite plugin that adds the Sentry Vite plugin and validates source map settings.
*/
export function createSentryViteConfigPlugin(options: {
nuxt: Nuxt;
moduleOptions: SentryNuxtModuleOptions;
sourceMapsEnabled: boolean;
shouldDeleteFilesFallback: { client: boolean; server: boolean };
}): Plugin {
const { nuxt, moduleOptions, sourceMapsEnabled, shouldDeleteFilesFallback } = options;
const isDebug = moduleOptions.debug;

return {
name: 'sentry-nuxt-vite-config',
config(viteConfig: UserConfig, env: ConfigEnv) {
// Only run in production builds
if (!sourceMapsEnabled || env.mode === 'development' || nuxt.options?._prepare) {
return;
}

// Detect runtime from Vite config
// In Nuxt, SSR builds have build.ssr: true, client builds don't
const runtime = viteConfig.build?.ssr ? 'server' : 'client';

const nuxtSourceMapSetting = extractNuxtSourceMapSetting(nuxt, runtime);

// Initialize build config if needed
viteConfig.build = viteConfig.build || {};
const viteSourceMap = viteConfig.build.sourcemap;

// Vite source map options are the same as the Nuxt source map config options (unless overwritten)
validateDifferentSourceMapSettings({
nuxtSettingKey: `sourcemap.${runtime}`,
nuxtSettingValue: nuxtSourceMapSetting,
otherSettingKey: 'viteConfig.build.sourcemap',
otherSettingValue: viteSourceMap,
});

if (isDebug) {
// eslint-disable-next-line no-console
console.log(`[Sentry] Adding Sentry Vite plugin to the ${runtime} runtime.`);
}

// Add Sentry plugin by mutating the config
// Vite plugin is added on the client and server side (plugin runs for both builds)
// Nuxt client source map is 'false' by default. Warning about this will be shown already in an earlier step, and it's also documented that `nuxt.sourcemap.client` needs to be enabled.
viteConfig.plugins = viteConfig.plugins || [];
viteConfig.plugins.push(sentryVitePlugin(getPluginOptions(moduleOptions, shouldDeleteFilesFallback)));
},
};
}
72 changes: 30 additions & 42 deletions packages/nuxt/src/vite/sourceMaps.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import type { Nuxt } from '@nuxt/schema';
import { sentryRollupPlugin, type SentryRollupPluginOptions } from '@sentry/rollup-plugin';
import { sentryVitePlugin, type SentryVitePluginOptions } from '@sentry/vite-plugin';
import type { SentryVitePluginOptions } from '@sentry/vite-plugin';
import type { NitroConfig } from 'nitropack';
import type { Plugin } from 'vite';
import type { SentryNuxtModuleOptions } from '../common/types';
import { createSentryViteConfigPlugin } from './sentryVitePlugin';

/**
* Whether the user enabled (true, 'hidden', 'inline') or disabled (false) source maps
Expand All @@ -15,7 +17,11 @@ export type SourceMapSetting = boolean | 'hidden' | 'inline';
/**
* Setup source maps for Sentry inside the Nuxt module during build time (in Vite for Nuxt and Rollup for Nitro).
*/
export function setupSourceMaps(moduleOptions: SentryNuxtModuleOptions, nuxt: Nuxt): void {
export function setupSourceMaps(
moduleOptions: SentryNuxtModuleOptions,
nuxt: Nuxt,
addVitePlugin: (plugin: Plugin | (() => Plugin), options?: { dev?: boolean; build?: boolean }) => void,
): void {
// TODO(v11): remove deprecated options (also from SentryNuxtModuleOptions type)

const isDebug = moduleOptions.debug;
Expand All @@ -32,7 +38,7 @@ export function setupSourceMaps(moduleOptions: SentryNuxtModuleOptions, nuxt: Nu
(sourceMapsUploadOptions.enabled ?? true);

// In case we overwrite the source map settings, we default to deleting the files
let shouldDeleteFilesFallback = { client: true, server: true };
const shouldDeleteFilesFallback = { client: true, server: true };

nuxt.hook('modules:done', () => {
if (sourceMapsEnabled && !nuxt.options.dev && !nuxt.options?._prepare) {
Expand All @@ -41,13 +47,12 @@ export function setupSourceMaps(moduleOptions: SentryNuxtModuleOptions, nuxt: Nu
// - for server to viteConfig.build.sourceMap and nitro.sourceMap
// On server, nitro.rollupConfig.output.sourcemap remains unaffected from this change.

// ONLY THIS nuxt.sourcemap.(server/client) setting is the one Sentry will eventually overwrite with 'hidden'
// ONLY THIS nuxt.sourcemap.(server/client) setting is the one Sentry will overwrite with 'hidden', if needed.
const previousSourceMapSettings = changeNuxtSourceMapSettings(nuxt, moduleOptions);

shouldDeleteFilesFallback = {
client: previousSourceMapSettings.client === 'unset',
server: previousSourceMapSettings.server === 'unset',
};
// Mutate in place so the Vite plugin (which captured this object at registration time) sees the updated values
shouldDeleteFilesFallback.client = previousSourceMapSettings.client === 'unset';
shouldDeleteFilesFallback.server = previousSourceMapSettings.server === 'unset';

if (isDebug && (shouldDeleteFilesFallback.client || shouldDeleteFilesFallback.server)) {
const enabledDeleteFallbacks =
Expand Down Expand Up @@ -76,39 +81,16 @@ export function setupSourceMaps(moduleOptions: SentryNuxtModuleOptions, nuxt: Nu
}
});

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

viteConfig.build = viteConfig.build || {};
const viteSourceMap = viteConfig.build.sourcemap;

// Vite source map options are the same as the Nuxt source map config options (unless overwritten)
validateDifferentSourceMapSettings({
nuxtSettingKey: `sourcemap.${runtime}`,
nuxtSettingValue: nuxtSourceMapSetting,
otherSettingKey: 'viteConfig.build.sourcemap',
otherSettingValue: viteSourceMap,
});

if (isDebug) {
if (!runtime) {
// eslint-disable-next-line no-console
console.log("[Sentry] Cannot detect runtime (client/server) inside hook 'vite:extendConfig'.");
} else {
// eslint-disable-next-line no-console
console.log(`[Sentry] Adding Sentry Vite plugin to the ${runtime} runtime.`);
}
}

// Add Sentry plugin
// Vite plugin is added on the client and server side (hook runs twice)
// Nuxt client source map is 'false' by default. Warning about this will be shown already in an earlier step, and it's also documented that `nuxt.sourcemap.client` needs to be enabled.
viteConfig.plugins = viteConfig.plugins || [];
viteConfig.plugins.push(sentryVitePlugin(getPluginOptions(moduleOptions, shouldDeleteFilesFallback)));
}
});
addVitePlugin(
createSentryViteConfigPlugin({
nuxt,
moduleOptions,
sourceMapsEnabled,
shouldDeleteFilesFallback,
}),
// Only add source map plugin during build
{ dev: false, build: true },
);

nuxt.hook('nitro:config', (nitroConfig: NitroConfig) => {
if (sourceMapsEnabled && !nitroConfig.dev && !nuxt.options?._prepare) {
Expand Down Expand Up @@ -379,7 +361,13 @@ export function validateNitroSourceMapSettings(
}
}

function validateDifferentSourceMapSettings({
/**
* Validates that source map settings are consistent between Nuxt and Vite/Nitro configurations.
* Logs a warning if conflicting settings are detected.
*
* @internal Only exported for testing.
*/
export function validateDifferentSourceMapSettings({
nuxtSettingKey,
nuxtSettingValue,
otherSettingKey,
Expand Down
Loading
Loading