DEV Community

Daniel Pertu
Daniel Pertu

Posted on

Our Sentry config sets one option the SDK has deleted and two more under a key whose own type says it has no effect

CogniPrep's next.config.mjs ends with this:

export default withSentryConfig(configWithAnalyzer, {
  org: 'pertu-works',
  project: 'cogniprep',
  silent: !process.env.CI,

  // OPTIMIZED: Reduced from true to false to decrease bundle size
  widenClientFileUpload: false,

  // Hide source maps from being sent to the client (reduces bundle size)
  hideSourceMaps: true,

  webpack: {
    automaticVercelMonitors: true,
    treeshake: {
      // Automatically tree-shake Sentry logger statements to reduce bundle size
      removeDebugLogging: true,
    },
  },
});
Enter fullscreen mode Exit fullscreen mode

Three comments, all of them about bundle size. next build on this project compiles with Turbopack, which is the default builder in Next 16. Here is what each line is worth.

The option that no longer exists

grep -rl "hideSourceMaps" node_modules/@sentry/ | wc -l
# 0
Enter fullscreen mode Exit fullscreen mode

Zero files. Not in the types, not in the compiled code, nowhere in any @sentry/* package at version 10.66.0. It was a real option years ago, when its job was to set webpack's devtool to hidden-source-map so the emitted bundles carried no //# sourceMappingURL comment. The modern SDK handles the same concern differently, with sourcemaps.deleteSourcemapsAfterUpload, which the types say defaults to true: maps are generated, uploaded to Sentry, then deleted from the build output.

So source maps are indeed not reachable from production:

curl -s -o /dev/null -w '%{http_code}\n' https://cogniprep.app/_next/static/chunks/07eegciq7b13p.js.map
# 404
Enter fullscreen mode Exit fullscreen mode

That 404 is the default doing its job. The line in our config contributed nothing to it.

The two options scoped to the wrong bundler

automaticVercelMonitors and treeshake are real, and they live inside the webpack key because that is where the SDK's types put them. Here is the doc comment attached to that key, straight out of node_modules:

/**
 * Options related to webpack builds, has no effect if you are using Turbopack.
 */
webpack?: SentryBuildWebpackOptions;
Enter fullscreen mode Exit fullscreen mode

The SDK is telling you, in the file your editor reads for autocomplete, that this entire object is inert on a Turbopack build. The same type file has the Turbopack replacements elsewhere:

  • cron monitors move to _experimental.vercelCronsMonitoring, described as "Automatically instrument Vercel Cron Jobs in the App Router with Sentry Cron Monitors"
  • excludeServerRoutes carries its own warning: "If you build Next.js with turbopack, the Sentry SDK will no longer apply build-time instrumentation ... this option will effectively no-op"

automaticVercelMonitors was dead twice over here, incidentally. Our own comment next to it, copied from Sentry's setup docs, reads "(Does not yet work with App Router route handlers.)" and all three of this project's crons are App Router route handlers. A webpack build would not have given us cron monitors either.

Measuring the one that is measurable

removeDebugLogging is the only inert option with a visible fingerprint, because the logger statements it strips are strings in the browser bundle. This site loads the Sentry SDK on the first idle moment rather than during hydration, so the chunk is not in the HTML: let the page settle, then read the resource timings and fetch the chunk back.

// in DevTools on any page of the site, after a few seconds
const js = performance.getEntriesByType('resource')
  .filter(e => /\.js(\?|$)/.test(e.name));
for (const e of js) {
  const t = await (await fetch(e.name)).text();
  if (/Sentry Logger/.test(t)) console.log(e.name, t.length);
}
Enter fullscreen mode Exit fullscreen mode

One hit, and it is the big one:

Chunk Transferred Decoded Sentry Logger
/_next/static/chunks/0~--mpio3n2-u.js 192,095 602,944 present

The surviving code is the logger factory itself:

function ep(e,...t){es&&ed()&&ec(()=>{en.console[e](`Sentry Logger [${e}]:`,...t)})}
Enter fullscreen mode Exit fullscreen mode

Harmless at runtime: the gate in front of it defaults to disabled, so nothing prints. But it is 600 KB of decoded JavaScript in which the thing we asked the build to delete is still sitting, which is the clearest possible proof that the webpack block never ran.

Two other things fell out of the same measurement. Every chunk ends with a //# debugId= comment, which is the Turbopack-compatible side of the Sentry build doing exactly what it should: debug IDs are how uploaded maps get matched to minified frames now, no source map URL required. And Session Replay is not in that 600 KB at all, because the client config attaches it with lazyLoadIntegration, which fetches it from Sentry's CDN at https://browser.sentry-cdn.com/10.66.0/replay.min.js. Worth knowing if you have ever written a CSP with script-src 'self' and wondered why your replays stopped.

Why four wrong lines survived a typed codebase

This project runs tsc --noEmit in its verify script, and the Sentry options object is a closed type with no index signature, so hideSourceMaps would be a compile error in a TypeScript file. The config is next.config.mjs, and tsconfig.json includes this:

"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ...]
Enter fullscreen mode Exit fullscreen mode

No .mjs. The one file in the repository that configures the bundler, the image optimizer, the CSP and the error monitoring is the one file the type checker never opens. The file even knows the trick, because the Next config object above it carries a JSDoc annotation:

/** @type {import('next').NextConfig} */
const nextConfig = { ... };
Enter fullscreen mode Exit fullscreen mode

The Sentry object has none, and .mjs is outside include anyway, so the annotation that exists is also unchecked.

What I am changing

  1. Delete hideSourceMaps. It describes behaviour the SDK now gets from a default.
  2. Delete the webpack block, and if we want cron monitors, set _experimental.vercelCronsMonitoring instead and verify a check-in arrives before believing the config.
  3. Keep widenClientFileUpload: false, which is real and applies to both bundlers, but fix the comment: it controls which files' source maps get uploaded, not what ships to the browser.
  4. Rename the file to next.config.ts so the next wrong option is a build failure rather than a comment.

The pattern underneath all of it is the one this project already met once, when a PWA plugin configured with two performance flags turned out to have emitted no service worker since the Turbopack migration. Bundler-scoped config does not fail when the bundler changes. It just stops being true, and the comment above it keeps making a promise.

See it

Open DevTools on any page of the live site, wait a few seconds for the idle load, then paste the snippet above into the console: the Sentry chunk and its leftover logger strings are reachable from the homepage, the pricing page or a provider page, and the Network panel shows replay.min.js arriving from Sentry's CDN rather than from us. The 404 on any .js.map is a one-line curl against the chunk URLs in the HTML of the games index, and the //# debugId= comment is on the last line of every one of those chunks.

Top comments (0)