import { sentryRollupPlugin } from '@sentry/rollup-plugin'; import { sentryVitePlugin } from '@sentry/vite-plugin'; import { withoutSourceMapDeletion, deleteSourceMapsAfterBuild } from './sourceMapDeletion.js'; import { validateSourceMapsOptionsPlugin } from './sentryVitePlugin.js'; function setupSourceMaps(moduleOptions, nuxt, addVitePlugin) { const isDebug = moduleOptions.debug; const sourceMapsUploadOptions = moduleOptions.sourceMapsUploadOptions || {}; const sourceMapsEnabled = moduleOptions.sourcemaps?.disable === true ? false : moduleOptions.sourcemaps?.disable === false ? true : ( // eslint-disable-next-line typescript/no-deprecated sourceMapsUploadOptions.enabled ?? true ); const shouldDeleteFilesFallback = { client: true, server: true }; nuxt.hook("modules:done", () => { if (sourceMapsEnabled && !nuxt.options.dev && !nuxt.options?._prepare) { const previousSourceMapSettings = changeNuxtSourceMapSettings(nuxt, moduleOptions); shouldDeleteFilesFallback.client = previousSourceMapSettings.client === "unset"; shouldDeleteFilesFallback.server = previousSourceMapSettings.server === "unset"; 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 typescript/no-deprecated !sourceMapsUploadOptions.sourcemaps?.filesToDeleteAfterUpload) { 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 { 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.` ); } } } }); if (sourceMapsEnabled && !nuxt.options.dev && !nuxt.options?._prepare) { addVitePlugin([validateSourceMapsOptionsPlugin({ nuxt, moduleOptions, sourceMapsEnabled })], { dev: false, build: true }); addVitePlugin( sentryVitePlugin(withoutSourceMapDeletion(getPluginOptions(moduleOptions, shouldDeleteFilesFallback))), // Nitro bundles the SSR output again, so debug IDs from the SSR build would point to the wrong maps. { dev: false, build: true, server: false } ); } nuxt.hook("nitro:config", (nitroConfig) => { if (sourceMapsEnabled && !nitroConfig.dev && !nuxt.options?._prepare) { nitroConfig.rollupConfig ?? (nitroConfig.rollupConfig = {}); if (nitroConfig.rollupConfig.plugins === null || nitroConfig.rollupConfig.plugins === void 0) { nitroConfig.rollupConfig.plugins = []; } else if (!Array.isArray(nitroConfig.rollupConfig.plugins)) { nitroConfig.rollupConfig.plugins = [nitroConfig.rollupConfig.plugins]; } validateNitroSourceMapSettings(nuxt, nitroConfig, moduleOptions); if (isDebug) { console.log("[Sentry] Adding Sentry Rollup plugin to the server runtime."); } nitroConfig.rollupConfig.plugins.push( sentryRollupPlugin(withoutSourceMapDeletion(getPluginOptions(moduleOptions, shouldDeleteFilesFallback))) ); } }); nuxt.hook("close", async () => { if (sourceMapsEnabled && !nuxt.options.dev && !nuxt.options?._prepare) { await deleteSourceMapsAfterBuild(getPluginOptions(moduleOptions, shouldDeleteFilesFallback)); } }); } function normalizePath(path) { return path.replace(/^(\.\.\/)+/, "./"); } function getPluginOptions(moduleOptions, shouldDeleteFilesFallback) { const sourceMapsUploadOptions = moduleOptions.sourceMapsUploadOptions || {}; const shouldDeleteFilesAfterUpload = shouldDeleteFilesFallback?.client || shouldDeleteFilesFallback?.server; const fallbackFilesToDelete = [ ...shouldDeleteFilesFallback?.client ? [".*/**/public/**/*.map"] : [], ...shouldDeleteFilesFallback?.server ? [".*/**/server/**/*.map", ".*/**/output/**/*.map", ".*/**/function/**/*.map"] : [] ]; const sourcemapsOptions = moduleOptions.sourcemaps || {}; const deprecatedSourcemapsOptions = sourceMapsUploadOptions.sourcemaps || {}; const filesToDeleteAfterUpload = sourcemapsOptions.filesToDeleteAfterUpload ?? // eslint-disable-next-line typescript/no-deprecated deprecatedSourcemapsOptions.filesToDeleteAfterUpload; if (typeof filesToDeleteAfterUpload === "undefined" && shouldDeleteFilesAfterUpload && moduleOptions.debug) { console.log( `[Sentry] Setting \`sentry.sourceMapsUploadOptions.sourcemaps.filesToDeleteAfterUpload: [${fallbackFilesToDelete.map((path) => `"${path}"`).join(", ")}]\` to delete generated source maps after they were uploaded to Sentry.` ); } return { applicationKey: moduleOptions.applicationKey, // eslint-disable-next-line typescript/no-deprecated org: moduleOptions.org ?? sourceMapsUploadOptions.org ?? process.env.SENTRY_ORG, // eslint-disable-next-line typescript/no-deprecated project: moduleOptions.project ?? sourceMapsUploadOptions.project ?? process.env.SENTRY_PROJECT, // eslint-disable-next-line typescript/no-deprecated authToken: moduleOptions.authToken ?? sourceMapsUploadOptions.authToken ?? process.env.SENTRY_AUTH_TOKEN, // eslint-disable-next-line typescript/no-deprecated telemetry: moduleOptions.telemetry ?? sourceMapsUploadOptions.telemetry ?? true, // eslint-disable-next-line typescript/no-deprecated url: moduleOptions.sentryUrl ?? sourceMapsUploadOptions.url ?? process.env.SENTRY_URL, headers: moduleOptions.headers, debug: moduleOptions.debug ?? false, // eslint-disable-next-line typescript/no-deprecated silent: moduleOptions.silent ?? sourceMapsUploadOptions.silent ?? false, // eslint-disable-next-line typescript/no-deprecated errorHandler: moduleOptions.errorHandler ?? sourceMapsUploadOptions.errorHandler, bundleSizeOptimizations: moduleOptions.bundleSizeOptimizations, // todo: test if this can be overridden by the user release: { // eslint-disable-next-line typescript/no-deprecated name: moduleOptions.release?.name ?? sourceMapsUploadOptions.release?.name, // Support all release options from BuildTimeOptionsBase ...moduleOptions.release, ...moduleOptions?.unstable_sentryBundlerPluginOptions?.release }, _metaOptions: { telemetry: { metaFramework: "nuxt" } }, ...moduleOptions?.unstable_sentryBundlerPluginOptions, sourcemaps: { disable: moduleOptions.sourcemaps?.disable, // The server/client files are in different places depending on the nitro preset (e.g. '.output/server' or '.netlify/functions-internal/server') // We cannot determine automatically how the build folder looks like (depends on the preset), so each plugin uploads its own build output (the vitePlugin for the Nuxt client and the rollupPlugin for Nitro). // If we could know where the server/client assets are located, we could do something like this (based on the Nitro preset): isNitro ? ['./.output/server/**/*'] : ['./.output/public/**/*'], // eslint-disable-next-line typescript/no-deprecated assets: sourcemapsOptions.assets ?? deprecatedSourcemapsOptions.assets ?? void 0, // eslint-disable-next-line typescript/no-deprecated ignore: sourcemapsOptions.ignore ?? deprecatedSourcemapsOptions.ignore ?? void 0, filesToDeleteAfterUpload: filesToDeleteAfterUpload ? filesToDeleteAfterUpload : shouldDeleteFilesFallback?.server || shouldDeleteFilesFallback?.client ? fallbackFilesToDelete : void 0, rewriteSources: sourcemapsOptions.rewriteSources ?? normalizePath, ...moduleOptions?.unstable_sentryBundlerPluginOptions?.sourcemaps } }; } function extractNuxtSourceMapSetting(nuxt, runtime) { if (!runtime) { return void 0; } else { return typeof nuxt.options?.sourcemap === "boolean" || typeof nuxt.options?.sourcemap === "string" ? nuxt.options.sourcemap : nuxt.options?.sourcemap?.[runtime]; } } function changeNuxtSourceMapSettings(nuxt, sentryModuleOptions) { nuxt.options.sourcemap = nuxt.options.sourcemap ?? { server: void 0, client: void 0 }; let previousUserSourceMapSetting = { client: void 0, server: void 0 }; const nuxtSourceMap = nuxt.options.sourcemap; const isDebug = sentryModuleOptions.debug; if (typeof nuxtSourceMap === "string" || typeof nuxtSourceMap === "boolean" || typeof nuxtSourceMap === "undefined") { switch (nuxtSourceMap) { case false: warnExplicitlyDisabledSourceMap("sourcemap", isDebug); previousUserSourceMapSetting = { client: "disabled", server: "disabled" }; break; case "hidden": case true: logKeepEnabledSourceMapSetting(sentryModuleOptions, "sourcemap", nuxtSourceMap.toString()); previousUserSourceMapSetting = { client: "enabled", server: "enabled" }; break; case void 0: nuxt.options.sourcemap = { server: "hidden", client: "hidden" }; isDebug && logSentryEnablesSourceMap("sourcemap.client", "hidden"); isDebug && logSentryEnablesSourceMap("sourcemap.server", "hidden"); previousUserSourceMapSetting = { client: "unset", server: "unset" }; break; } } else { if (nuxtSourceMap.client === false) { warnExplicitlyDisabledSourceMap("sourcemap.client", isDebug); previousUserSourceMapSetting.client = "disabled"; } else if (["hidden", true].includes(nuxtSourceMap.client)) { logKeepEnabledSourceMapSetting(sentryModuleOptions, "sourcemap.client", nuxtSourceMap.client.toString()); previousUserSourceMapSetting.client = "enabled"; } else { nuxt.options.sourcemap.client = "hidden"; isDebug && logSentryEnablesSourceMap("sourcemap.client", "hidden"); previousUserSourceMapSetting.client = "unset"; } if (nuxtSourceMap.server === false) { warnExplicitlyDisabledSourceMap("sourcemap.server", isDebug); previousUserSourceMapSetting.server = "disabled"; } else if (["hidden", true].includes(nuxtSourceMap.server)) { logKeepEnabledSourceMapSetting(sentryModuleOptions, "sourcemap.server", nuxtSourceMap.server.toString()); previousUserSourceMapSetting.server = "enabled"; } else { nuxt.options.sourcemap.server = "hidden"; isDebug && logSentryEnablesSourceMap("sourcemap.server", "hidden"); previousUserSourceMapSetting.server = "unset"; } } return previousUserSourceMapSetting; } function validateNitroSourceMapSettings(nuxt, nitroConfig, sentryModuleOptions) { const isDebug = sentryModuleOptions.debug; const nuxtSourceMap = extractNuxtSourceMapSetting(nuxt, "server"); validateDifferentSourceMapSettings({ nuxtSettingKey: "sourcemap.server", nuxtSettingValue: nuxtSourceMap, otherSettingKey: "nitro.sourceMap", otherSettingValue: nitroConfig.sourceMap }); nitroConfig.rollupConfig = nitroConfig.rollupConfig || {}; nitroConfig.rollupConfig.output = nitroConfig.rollupConfig.output || { sourcemap: void 0 }; const nitroRollupSourceMap = nitroConfig.rollupConfig.output.sourcemap; if (typeof nitroRollupSourceMap !== "undefined" && ["hidden", "inline", true, false].includes(nitroRollupSourceMap)) { const settingKey = "nitro.rollupConfig.output.sourcemap"; validateDifferentSourceMapSettings({ nuxtSettingKey: "sourcemap.server", nuxtSettingValue: nuxtSourceMap, otherSettingKey: settingKey, otherSettingValue: nitroRollupSourceMap }); } nitroConfig.rollupConfig.output.sourcemapExcludeSources = false; if (isDebug) { console.log( "[Sentry] Set `sourcemapExcludeSources: false` in the Nuxt config (`nitro.rollupConfig.output`). Source maps will now include the actual code to be able to un-minify code snippets in Sentry." ); } } function validateDifferentSourceMapSettings({ nuxtSettingKey, nuxtSettingValue, otherSettingKey, otherSettingValue }) { if (nuxtSettingValue !== otherSettingValue) { console.warn( `[Sentry] Source map generation settings are conflicting. Sentry uses \`${nuxtSettingKey}: ${nuxtSettingValue}\`. However, a conflicting setting was discovered (\`${otherSettingKey}: ${otherSettingValue}\`). This setting was probably explicitly set in your configuration. Sentry won't override this setting but it may affect source maps generation and upload. Without source maps, code snippets on the Sentry Issues page will remain minified.` ); } } function logKeepEnabledSourceMapSetting(sentryNuxtModuleOptions, settingKey, settingValue) { if (sentryNuxtModuleOptions.debug) { console.log( `[Sentry] \`${settingKey}\` is enabled with \`${settingValue}\`. This will correctly un-minify the code snippet on the Sentry Issue Details page.` ); } } function warnExplicitlyDisabledSourceMap(settingKey, isDebug) { if (isDebug) { console.warn( `[Sentry] Source map generation is currently disabled in your Vite configuration (\`${settingKey}: false \`). This setting is either a default setting or was explicitly set in your configuration. Sentry won't override this setting. Without source maps, code snippets on the Sentry Issues page will remain minified. To show unminified code, enable source maps in \`${settingKey}\` (e.g. by setting them to \`hidden\`).` ); } else { console.warn(`[Sentry] Source map generation (\`${settingKey}\`) is disabled in your Vite configuration.`); } } function logSentryEnablesSourceMap(settingKey, settingValue) { console.log(`[Sentry] Enabled source map generation in the build options with \`${settingKey}: ${settingValue}\`.`); } export { changeNuxtSourceMapSettings, extractNuxtSourceMapSetting, getPluginOptions, setupSourceMaps, validateDifferentSourceMapSettings, validateNitroSourceMapSettings }; //# sourceMappingURL=sourceMaps.js.map