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
3 changes: 2 additions & 1 deletion packages/nuxt/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@
"@sentry/core": "8.26.0",
"@sentry/node": "8.26.0",
"@sentry/opentelemetry": "8.26.0",
"@sentry/rollup-plugin": "2.22.1",
"@sentry/types": "8.26.0",
"@sentry/utils": "8.26.0",
"@sentry/vite-plugin": "2.20.1",
"@sentry/vite-plugin": "2.22.1",
"@sentry/vue": "8.26.0"
},
"devDependencies": {
Expand Down
111 changes: 78 additions & 33 deletions packages/nuxt/src/vite/sourceMaps.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,97 @@
import type { Nuxt } from '@nuxt/schema';
import { sentryRollupPlugin } from '@sentry/rollup-plugin';
import { 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.
*/
export function setupSourceMaps(moduleOptions: SentryNuxtModuleOptions, nuxt: Nuxt): void {
nuxt.hook('vite:extendConfig', async (viteInlineConfig, _env) => {
const sourceMapsUploadOptions = moduleOptions.sourceMapsUploadOptions || {};
const sourceMapsUploadOptions = moduleOptions.sourceMapsUploadOptions || {};
const sourceMapsEnabled = sourceMapsUploadOptions.enabled ?? true;

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,
});
nuxt.hook('vite:extendConfig', async (viteInlineConfig, _env) => {
if (sourceMapsEnabled && viteInlineConfig.mode !== 'development') {
const sentryPlugin = sentryVitePlugin(getPluginOptions(moduleOptions));

// Add Sentry plugin
viteInlineConfig.plugins = viteInlineConfig.plugins || [];
viteInlineConfig.plugins.push(sentryPlugin);

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

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`,
);
logDebugInfo(moduleOptions, viteInlineConfig.build?.sourcemap);
}
});

nuxt.hook('nitro:config', (nitroConfig: NitroConfig) => {
if (sourceMapsEnabled && !nitroConfig.dev) {
const sentryPlugin = sentryRollupPlugin(getPluginOptions(moduleOptions));
Copy link
Member

Choose a reason for hiding this comment

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

h: Can we move this assignment inside the if statment where we use the variable? In general I would avoid creating variables for things we only use once (unless it becomes absolutely unreadable). It tricks you into thinking something is used in more than one place.


if (nitroConfig.rollupConfig) {
// Add Sentry plugin
if (!Array.isArray(nitroConfig.rollupConfig.plugins)) {
nitroConfig.rollupConfig.plugins = 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.

Would you mind adding a short comment why we are overriding the plugins with themselves but as a single item in an array? 🤔 What is happening here?

Copy link
Member Author

Choose a reason for hiding this comment

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

According to the type it is not always an array and I am converting it to an array to .push the plugin later on

Copy link
Member

Choose a reason for hiding this comment

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

Question is, is converting it from whatever it is to an array safe?

}
}
nitroConfig.rollupConfig.plugins.push(sentryPlugin);

viteInlineConfig.build = viteInlineConfig.build || {};
viteInlineConfig.build.sourcemap = 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): object {
lforst marked this conversation as resolved.
Show resolved Hide resolved
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 ?? ['./.output/public/**/*', './.output/server/**/*'],
Copy link
Member

Choose a reason for hiding this comment

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

m: I am wondering whether we will upload the same exact thing twice here because the plugin runs two times, one for nitro and one for nuxt. Is there a way we can avoid (too much) duplication? Sometimes it's unavoidable but here it might be possible to avoid it.

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.
[Sentry] Otherwise, source maps might be deployed to production, depending on your configuration`,
lforst marked this conversation as resolved.
Show resolved Hide resolved
);
}
}
}
51 changes: 43 additions & 8 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8195,6 +8195,11 @@
resolved "https://registry.yarnpkg.com/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-2.22.0.tgz#a7e1cc99d1a738d1eb17757341dff4db3a93c2dc"
integrity sha512-UzH+NNhgnOo6UFku3C4TEz+pO/yDcIA5FKTJvLbJ7lQwAjsqLs3DZWm4cCA08skICb8mULArF6S/dn5/butVCA==

"@sentry/babel-plugin-component-annotate@2.22.1":
version "2.22.1"
resolved "https://registry.yarnpkg.com/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-2.22.1.tgz#2877af31f1d0358202593fe6d14141827a2f1e42"
integrity sha512-rQEk8EeCIBQKivWNONllQhd/wGbfuK/WXJRM6TkjeikM3wrqJf4AmIBXoA6eg089DwBFzBaxGjjLWJNHKY440w==

"@sentry/bundler-plugin-core@2.16.0":
version "2.16.0"
resolved "https://registry.yarnpkg.com/@sentry/bundler-plugin-core/-/bundler-plugin-core-2.16.0.tgz#0c33e7a054fb56e43bd160ac141f71dfebf6dda5"
Expand Down Expand Up @@ -8251,6 +8256,20 @@
magic-string "0.30.8"
unplugin "1.0.1"

"@sentry/bundler-plugin-core@2.22.1":
version "2.22.1"
resolved "https://registry.yarnpkg.com/@sentry/bundler-plugin-core/-/bundler-plugin-core-2.22.1.tgz#a3c984fd0e6a7bc3977cd74a635f6222e69c4ef2"
integrity sha512-RFbS57zfPvUBe4DL/pjt6BWCEyGFkk/n4gLNZQ9Cf2gRdUVW80AtAMZwrlEELrpW1D8kONy6/kvWf0leicHRMg==
dependencies:
"@babel/core" "^7.18.5"
"@sentry/babel-plugin-component-annotate" "2.22.1"
"@sentry/cli" "^2.33.1"
dotenv "^16.3.1"
find-up "^5.0.0"
glob "^9.3.2"
magic-string "0.30.8"
unplugin "1.0.1"

"@sentry/cli-darwin@2.33.0":
version "2.33.0"
resolved "https://registry.yarnpkg.com/@sentry/cli-darwin/-/cli-darwin-2.33.0.tgz#c0f3352a9e58e4f02deca52f0d5a9bd14b3e4a32"
Expand Down Expand Up @@ -8359,6 +8378,14 @@
"@sentry/cli-win32-i686" "2.33.1"
"@sentry/cli-win32-x64" "2.33.1"

"@sentry/rollup-plugin@2.22.1":
version "2.22.1"
resolved "https://registry.yarnpkg.com/@sentry/rollup-plugin/-/rollup-plugin-2.22.1.tgz#644e6e47d4130bca31a578782813835ca243a484"
integrity sha512-ytioqf5e9lyuDc4G8cK0kMtl6DUUuPaE2ob583esnzEw/X15fpvdJOkBDNbyCtOrArm8me8o5lM47vi6FTv1vA==
dependencies:
"@sentry/bundler-plugin-core" "2.22.1"
unplugin "1.0.1"

"@sentry/vite-plugin@2.19.0":
version "2.19.0"
resolved "https://registry.yarnpkg.com/@sentry/vite-plugin/-/vite-plugin-2.19.0.tgz#c7938fb13eee15036963b87d7b12c4fc851e488b"
Expand All @@ -8367,14 +8394,6 @@
"@sentry/bundler-plugin-core" "2.19.0"
unplugin "1.0.1"

"@sentry/vite-plugin@2.20.1", "@sentry/vite-plugin@^2.20.1":
version "2.20.1"
resolved "https://registry.yarnpkg.com/@sentry/vite-plugin/-/vite-plugin-2.20.1.tgz#80d5639fca3f68fbf81c316883272ffb34dbc544"
integrity sha512-IOYAJRcV+Uqn0EL8rxcoCvE77PbtGzKjP+B6iIgDZ229AWbpfbpWY8zHCcufwdDzb5PtgOhWWHT74iAsNyij/A==
dependencies:
"@sentry/bundler-plugin-core" "2.20.1"
unplugin "1.0.1"

"@sentry/vite-plugin@2.22.0":
version "2.22.0"
resolved "https://registry.yarnpkg.com/@sentry/vite-plugin/-/vite-plugin-2.22.0.tgz#09743ac390cf8c1609f2fa6d5424548d0b6f7928"
Expand All @@ -8383,6 +8402,22 @@
"@sentry/bundler-plugin-core" "2.22.0"
unplugin "1.0.1"

"@sentry/vite-plugin@2.22.1":
version "2.22.1"
resolved "https://registry.yarnpkg.com/@sentry/vite-plugin/-/vite-plugin-2.22.1.tgz#66192485440fd7f3726279a6bda2de4e59e6fd13"
integrity sha512-TC+3RIcu0rnxaEPV8ZHjYlRHLx5M9eRDI2il1lFkSguTc0N89n7Tt/aDnFAwtaPG4yqPkhIMpxi7LfXx+YDJ1Q==
dependencies:
"@sentry/bundler-plugin-core" "2.22.1"
unplugin "1.0.1"

"@sentry/vite-plugin@^2.20.1":
version "2.20.1"
resolved "https://registry.yarnpkg.com/@sentry/vite-plugin/-/vite-plugin-2.20.1.tgz#80d5639fca3f68fbf81c316883272ffb34dbc544"
integrity sha512-IOYAJRcV+Uqn0EL8rxcoCvE77PbtGzKjP+B6iIgDZ229AWbpfbpWY8zHCcufwdDzb5PtgOhWWHT74iAsNyij/A==
dependencies:
"@sentry/bundler-plugin-core" "2.20.1"
unplugin "1.0.1"

"@sentry/webpack-plugin@2.16.0":
version "2.16.0"
resolved "https://registry.yarnpkg.com/@sentry/webpack-plugin/-/webpack-plugin-2.16.0.tgz#4764577edb10c9575a8b4ce03135493f995f56b9"
Expand Down
Loading