Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(nuxt): Upload sourcemaps generated by Nitro #13382

Merged
merged 10 commits into from
Sep 4, 2024
1 change: 1 addition & 0 deletions packages/nuxt/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"@sentry/core": "8.28.0",
"@sentry/node": "8.28.0",
"@sentry/opentelemetry": "8.28.0",
"@sentry/rollup-plugin": "2.22.3",
"@sentry/types": "8.28.0",
"@sentry/utils": "8.28.0",
"@sentry/vite-plugin": "2.22.3",
Expand Down
126 changes: 88 additions & 38 deletions packages/nuxt/src/vite/sourceMaps.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,102 @@
import type { Nuxt } from '@nuxt/schema';
import { sentryVitePlugin } from '@sentry/vite-plugin';
import { type SentryRollupPluginOptions, sentryRollupPlugin } from '@sentry/rollup-plugin';
import { type SentryVitePluginOptions, sentryVitePlugin } from '@sentry/vite-plugin';
import type { NitroConfig } from 'nitropack';
import type { SentryNuxtModuleOptions } from '../common/types';

/**
* Setup source maps for Sentry inside the Nuxt module during build time.
* 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 {
nuxt.hook('vite:extendConfig', async (viteInlineConfig, _env) => {
const sourceMapsUploadOptions = moduleOptions.sourceMapsUploadOptions || {};

if ((sourceMapsUploadOptions.enabled ?? true) && viteInlineConfig.mode !== 'development') {
const sentryPlugin = sentryVitePlugin({
org: sourceMapsUploadOptions.org ?? process.env.SENTRY_ORG,
project: sourceMapsUploadOptions.project ?? process.env.SENTRY_PROJECT,
authToken: sourceMapsUploadOptions.authToken ?? process.env.SENTRY_AUTH_TOKEN,
telemetry: sourceMapsUploadOptions.telemetry ?? true,
sourcemaps: {
assets: sourceMapsUploadOptions.sourcemaps?.assets ?? undefined,
ignore: sourceMapsUploadOptions.sourcemaps?.ignore ?? undefined,
filesToDeleteAfterUpload: sourceMapsUploadOptions.sourcemaps?.filesToDeleteAfterUpload ?? undefined,
},
_metaOptions: {
telemetry: {
metaFramework: 'nuxt',
},
},
debug: moduleOptions.debug ?? false,
});
const sourceMapsUploadOptions = moduleOptions.sourceMapsUploadOptions || {};
const sourceMapsEnabled = sourceMapsUploadOptions.enabled ?? true;

nuxt.hook('vite:extendConfig', async (viteInlineConfig, _env) => {
if (sourceMapsEnabled && viteInlineConfig.mode !== 'development') {
// Add Sentry plugin
viteInlineConfig.plugins = viteInlineConfig.plugins || [];
viteInlineConfig.plugins.push(sentryPlugin);

const sourceMapsPreviouslyEnabled = viteInlineConfig.build?.sourcemap;

if (moduleOptions.debug && !sourceMapsPreviouslyEnabled) {
// eslint-disable-next-line no-console
console.log('[Sentry]: Enabled source maps generation in the Vite build options.');
if (!moduleOptions.sourceMapsUploadOptions?.sourcemaps?.filesToDeleteAfterUpload) {
// eslint-disable-next-line no-console
console.warn(
`[Sentry] We recommend setting the \`sourceMapsUploadOptions.sourcemaps.filesToDeleteAfterUpload\` option to clean up source maps after uploading.
[Sentry] Otherwise, source maps might be deployed to production, depending on your configuration`,
);
}
}
viteInlineConfig.plugins.push(sentryVitePlugin(getPluginOptions(moduleOptions)));

// Enable source maps
viteInlineConfig.build = viteInlineConfig.build || {};
viteInlineConfig.build.sourcemap = true;

logDebugInfo(moduleOptions, viteInlineConfig.build?.sourcemap);
}
});

nuxt.hook('nitro:config', (nitroConfig: NitroConfig) => {
if (sourceMapsEnabled && !nitroConfig.dev) {
if (!nitroConfig.rollupConfig) {
nitroConfig.rollupConfig = {};
}

if (nitroConfig.rollupConfig.plugins === null || nitroConfig.rollupConfig.plugins === undefined) {
nitroConfig.rollupConfig.plugins = [];
} else if (!Array.isArray(nitroConfig.rollupConfig.plugins)) {
// `rollupConfig.plugins` can be a single plugin, so we want to put it into an array so that we can push our own plugin
nitroConfig.rollupConfig.plugins = [nitroConfig.rollupConfig.plugins];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: Maybe we can leave a comment saying something along the lines of "nitroConfig.rollupConfig.plugins can be a singular plugin, in the case of which we want to put it into an array so that we can push our own plugin"

}

// Add Sentry plugin
nitroConfig.rollupConfig.plugins.push(sentryRollupPlugin(getPluginOptions(moduleOptions, true)));

// Enable source maps
nitroConfig.rollupConfig.output = nitroConfig?.rollupConfig?.output || {};
nitroConfig.rollupConfig.output.sourcemap = true;
nitroConfig.rollupConfig.output.sourcemapExcludeSources = false; // Adding "sourcesContent" to the source map (Nitro sets this eto `true`)

logDebugInfo(moduleOptions, nitroConfig.rollupConfig.output?.sourcemap);
}
});
}

/**
* Normalizes the beginning of a path from e.g. ../../../ to ./
*/
function normalizePath(path: string): string {
return path.replace(/^(\.\.\/)+/, './');
}

function getPluginOptions(
moduleOptions: SentryNuxtModuleOptions,
isNitro = false,
): SentryVitePluginOptions | SentryRollupPluginOptions {
const sourceMapsUploadOptions = moduleOptions.sourceMapsUploadOptions || {};

return {
org: sourceMapsUploadOptions.org ?? process.env.SENTRY_ORG,
project: sourceMapsUploadOptions.project ?? process.env.SENTRY_PROJECT,
authToken: sourceMapsUploadOptions.authToken ?? process.env.SENTRY_AUTH_TOKEN,
telemetry: sourceMapsUploadOptions.telemetry ?? true,
sourcemaps: {
assets:
sourceMapsUploadOptions.sourcemaps?.assets ?? isNitro ? ['./.output/server/**/*'] : ['./.output/public/**/*'],
ignore: sourceMapsUploadOptions.sourcemaps?.ignore ?? undefined,
filesToDeleteAfterUpload: sourceMapsUploadOptions.sourcemaps?.filesToDeleteAfterUpload ?? undefined,
rewriteSources: (source: string) => normalizePath(source),
},
_metaOptions: {
telemetry: {
metaFramework: 'nuxt',
},
},
debug: moduleOptions.debug ?? false,
};
}

function logDebugInfo(moduleOptions: SentryNuxtModuleOptions, sourceMapsPreviouslyEnabled: boolean): void {
if (moduleOptions.debug && !sourceMapsPreviouslyEnabled) {
// eslint-disable-next-line no-console
console.log('[Sentry]: Enabled source maps generation in the Vite build options.');

const sourceMapsUploadOptions = moduleOptions.sourceMapsUploadOptions || {};

if (!sourceMapsUploadOptions.sourcemaps?.filesToDeleteAfterUpload) {
// eslint-disable-next-line no-console
console.warn(
'[Sentry] 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',
);
}
}
}
8 changes: 8 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8309,6 +8309,14 @@
"@sentry/cli-win32-i686" "2.33.1"
"@sentry/cli-win32-x64" "2.33.1"

"@sentry/rollup-plugin@2.22.3":
version "2.22.3"
resolved "https://registry.yarnpkg.com/@sentry/rollup-plugin/-/rollup-plugin-2.22.3.tgz#18ab4b7903ee723bee4cf789b38bb3febb05faae"
integrity sha512-I1UsnYzZm5W7/Pyah2yxuMRxmzgf5iDKoptFfMaerpRO5oBhFO3tMnKSLAlYMvuXKRoYkInNv6ckkUcSOF6jig==
dependencies:
"@sentry/bundler-plugin-core" "2.22.3"
unplugin "1.0.1"

"@sentry/vite-plugin@2.22.3", "@sentry/vite-plugin@^2.22.3":
version "2.22.3"
resolved "https://registry.yarnpkg.com/@sentry/vite-plugin/-/vite-plugin-2.22.3.tgz#b52802412b6f3d8e3e56742afc9624d9babae5b6"
Expand Down
Loading