Repository navigation
Description
Problem
Setting up source map upload with the Sentry bundler plugins needs too much configuration, and most of it is about source maps that users do not want to ship. The current Vite docs example:
import { defineConfig } from "vite";
import { sentryVitePlugin } from "@sentry/vite-plugin";
export default defineConfig({
build: {
sourcemap: "hidden", // Source map generation must be turned on ("hidden", true, etc.)
},
plugins: [
sentryVitePlugin({
org: "example-org",
project: "example-project",
authToken: process.env.SENTRY_AUTH_TOKEN,
sourcemaps: {
// As you're enabling client source maps, you probably want to delete them after they're uploaded to Sentry.
// Set the appropriate glob pattern for your output folder - some glob examples below:
filesToDeleteAfterUpload: ["./**/*.map", ".*/**/public/**/*.map", "./dist/**/client/**/*.map"],
},
}),
],
});Users have to know three things: that source maps must be turned on, that hidden is the right mode, and which glob matches their output folder. Wrong globs either leave maps in production or delete files that were never uploaded.
The plugins upload from disk after the bundler has written its output, then delete files that match the globs. The bundlers all expose the generated map to plugins before the write (generateBundle in Rollup, Rolldown and Vite, processAssets in webpack and Rspack), so the plugin does not need the map on disk at all.
Proposal
Add one option, sourcemaps.deleteSourcemapsAfterUpload?: boolean, default undefined ("auto"), and make the plugin handle the source map setting itself:
| Bundler source map setting | deleteSourcemapsAfterUpload |
Behaviour |
|---|---|---|
| unset | auto or true |
Plugin turns on hidden maps, copies each chunk and its map from the bundler's pre-write hook into the temp upload folder, removes the .map asset so it is never written, uploads the temp folder. |
| unset | false |
Unchanged: setting untouched, no maps generated. |
hidden or true |
auto | Unchanged: upload from disk, maps stay in the output, filesToDeleteAfterUpload still works. |
hidden or true |
true |
true is coerced to hidden. Maps are removed before write. |
inline |
any | Warn. Nothing to delete. |
false |
any | Warn that source maps are off. |
Rules:
- The plugin only turns maps on when it will also remove them.
falsenever adds maps to anyone's output. - The plugin only turns maps on when an upload can run (not
NODE_ENV=development,sourcemaps.disableunset, auth token, org and project present). Builds without credentials behave as today. - For Rollup, Rolldown, Vite, webpack and Rspack the
.mapfile is never written to the output directory. For esbuild, which has no pre-write hook, the plugin deletes the exact.mappaths from esbuild's metafile after a successful upload. - Existing
filesToDeleteAfterUploadglobs keep working and are still useful for files the bundler did not produce.
What the docs become
import { defineConfig } from "vite";
import { sentryVitePlugin } from "@sentry/vite-plugin";
export default defineConfig({
plugins: [
sentryVitePlugin({
org: "example-org",
project: "example-project",
authToken: process.env.SENTRY_AUTH_TOKEN,
}),
],
});No build.sourcemap line, no globs, no comment explaining either. The same applies to the Rollup, webpack, Rspack and esbuild pages. The "delete source maps after upload" docs section shrinks to one sentence: maps are uploaded and not shipped by default; set sourcemaps.deleteSourcemapsAfterUpload: false to keep them.
Backwards compatibility
- Anyone who set
hiddenortruetoday sees no change. - Anyone with
sourcemapunset and credentials configured gets maps uploaded where they got a "no source maps found" warning before. Their emitted JavaScript does not change and no.mapfile appears in their output. - The framework SDKs (Next.js, Nuxt, SvelteKit, Astro, Remix, SolidStart, TanStack Start, Gatsby) pass
deleteSourcemapsAfterUpload: falsein the first PR so their existing behaviour is untouched. Each SDK can then drop its own hidden-map and glob logic in a follow-up PR. Nitro, React Router and Next.js Turbopack upload outside the bundler and keep their current approach.
Implementation notes
- The upload still goes through the Sentry CLI, which takes a directory, so the temp folder stays. Only the source of the bytes changes, from the output directory to the bundler's hook payload. Memory use does not grow because the bundler already holds every chunk and map for the hook.
- Rollup and Rolldown: an
outputOptionshook setssourcemap: 'hidden'when unset; a second plugin object withgenerateBundleatorder: 'post'stages the chunk and map and deletes the.mapasset. Rolldown syncs asset deletion back to Rust. - Vite: a
confighook setsbuild.sourcemap: 'hidden'when unset; the existingenforce: 'post'plugin does the staging aftervite:build-import-analysishas rewritten the maps. - webpack and Rspack:
apply()setsdevtool: 'hidden-source-map'when unset;processAssetsatPROCESS_ASSETS_STAGE_REPORT + 1stages the asset and itsrelated.sourceMapand callscompilation.deleteAsset. Content hashes are unaffected because they are final by then. - Rollup 4.64.8 now includes the
sourceMappingURLcomment in chunk hashes, so the plugin must use thehiddenmode rather than strip the comment itself. - Upstream, a native "generate but do not emit" source map mode would remove the need to force
hidden. Rolldown, webpack and Rspack look receptive and Next.js has an open request for a hidden mode in Turbopack (Add option to hide sourcemaps for client side bundle vercel/next.js#84095). That is separate work and this change does not depend on it.
Activity
linear-code commentedon Oct 21, 2026
JS-3980
feat(bundler-plugins): Add `sourcemaps.deleteSourcemapsAfterUpload` a…
feat(bundler-plugins): Enable hidden source maps and remove them afte…
feat(bundler-plugins): Enable hidden source maps and remove them afte…
feat(bundler-plugins): Enable hidden source maps and remove them afte…
feat(bundler-plugins): Enable external source maps and delete them af…