Skip to content

perf(build): Optimize terser minifier config for CDN bundles#19852

Open
HazAT wants to merge 1 commit intoautoresearch/browser-bundle-size-2026-03-17from
bundle-size/terser-config
Open

perf(build): Optimize terser minifier config for CDN bundles#19852
HazAT wants to merge 1 commit intoautoresearch/browser-bundle-size-2026-03-17from
bundle-size/terser-config

Conversation

@HazAT
Copy link
Member

@HazAT HazAT commented Mar 17, 2026

Summary

Enable additional terser compress and mangle options that safely reduce CDN .min.js bundle sizes. Saves ~300 bytes gzipped on the base browser bundle.

Changes

Option Effect
compress.passes: 5 Multi-pass optimization finds more dead code
compress.ecma: 2020 Allows modern syntax in output (nullish coalescing, optional chaining)
compress.toplevel: true Better variable inlining within the IIFE wrapper
compress.unsafe_arrows: true Converts function to => where this is unused (~1.3KB raw)
compress.unsafe_methods: true Shorthand method syntax { m(){} }
compress.unsafe_comps / unsafe_math / pure_getters Safe algebraic optimizations
mangle.toplevel: true Mangle top-level variable names inside IIFE scope

These options only affect CDN .min.js bundles, not npm ESM/CJS output. The unsafe_* options are safe for our codebase because the CDN bundles run in browser contexts where the assumptions hold.

Also pre-reserves sW in the mangle list for a follow-up change.

Part of #19833.

Co-Authored-By: Claude claude@anthropic.com

Enable additional terser compress and mangle options that safely reduce
the size of CDN bundle .min.js files:

- compress.passes: 5 (multi-pass finds more dead code)
- compress.ecma: 2020 (allows modern syntax: nullish coalescing, optional chaining)
- compress.toplevel: true (better variable inlining within the IIFE)
- compress.unsafe_arrows: true (function → arrow where this is unused, ~1.3KB raw)
- compress.unsafe_methods: true ({ m: function(){} } → { m(){} })
- compress.unsafe_comps/unsafe_math/pure_getters: safe algebraic opts
- mangle.toplevel: true (mangle top-level names inside IIFE scope)

Also adds 'sW' to the mangle reserved list (used by a follow-up change that
shortens the sentryWrapped function name for frame stripping).

These options only affect CDN .min.js bundles, not npm ESM/CJS output.
Saves ~300 bytes gzipped on the base browser bundle.

Co-Authored-By: Claude claude@anthropic.com
Comment on lines +104 to +105
reserved: ['captureException', 'captureMessage', 'sentryWrapped', 'sW'],
toplevel: true,
Copy link

Choose a reason for hiding this comment

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

Bug: Enabling mangle.toplevel: true may cause Terser to mangle the sentryWrapped function name due to a known bug, which will break internal stack trace filtering.
Severity: MEDIUM

Suggested Fix

To mitigate the risk from the Terser bug, either disable the mangle.toplevel: true option or find an alternative way to identify the sentryWrapped frame that does not rely on its function name remaining unmangled in the minified bundle.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: dev-packages/rollup-utils/plugins/bundlePlugins.mjs#L104-L105

Potential issue: Enabling the Terser option `mangle.toplevel: true` introduces a risk of
breaking stack trace filtering. A known bug in Terser can cause it to mangle function
names like `sentryWrapped` even when they are explicitly added to the `reserved` list.
This function is defined at the top level of an IIFE, making it susceptible to this bug.
If `sentryWrapped` is renamed, a regex check (`/sentryWrapped/`) used to filter internal
Sentry frames from stack traces will fail. This results in internal SDK frames appearing
in user-facing stack traces, which can degrade data quality and affect error grouping.

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

// are all listed here just for the clarity's sake, as they are all used in the frames manipulation process.
reserved: ['captureException', 'captureMessage', 'sentryWrapped'],
reserved: ['captureException', 'captureMessage', 'sentryWrapped', 'sW'],
toplevel: true,
Copy link

Choose a reason for hiding this comment

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

Toplevel mangling renames global Sentry IIFE variable

High Severity

The mangle.toplevel: true and compress.toplevel: true options will mangle or eliminate the top-level var Sentry declaration produced by rollup's IIFE format (name: 'Sentry' in bundleHelpers.mjs). Since Sentry is not in the reserved list, terser sees it as an unreferenced top-level variable (the window.Sentry inside the IIFE is a property access, not a variable reference) and will rename it to a shorter name. This breaks window.Sentry for all CDN bundle consumers.

Additional Locations (1)
Fix in Cursor Fix in Web

Copy link
Member

Choose a reason for hiding this comment

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

Confirmed that this is accurate. Strips out the var Sentry= prefix at the start of the rollup. I'll poke around to see if there's a workaround.

@github-actions
Copy link
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 25.64 kB added added
@sentry/browser - with treeshaking flags 24.14 kB added added
@sentry/browser (incl. Tracing) 42.62 kB added added
@sentry/browser (incl. Tracing, Profiling) 47.28 kB added added
@sentry/browser (incl. Tracing, Replay) 81.42 kB added added
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 71 kB added added
@sentry/browser (incl. Tracing, Replay with Canvas) 86.12 kB added added
@sentry/browser (incl. Tracing, Replay, Feedback) 98.37 kB added added
@sentry/browser (incl. Feedback) 42.45 kB added added
@sentry/browser (incl. sendFeedback) 30.31 kB added added
@sentry/browser (incl. FeedbackAsync) 35.36 kB added added
@sentry/browser (incl. Metrics) 26.92 kB added added
@sentry/browser (incl. Logs) 27.07 kB added added
@sentry/browser (incl. Metrics & Logs) 27.74 kB added added
@sentry/react 27.39 kB added added
@sentry/react (incl. Tracing) 44.95 kB added added
@sentry/vue 30.08 kB added added
@sentry/vue (incl. Tracing) 44.48 kB added added
@sentry/svelte 25.66 kB added added
CDN Bundle 28.1 kB added added
CDN Bundle (incl. Tracing) 43.18 kB added added
CDN Bundle (incl. Logs, Metrics) 28.95 kB added added
CDN Bundle (incl. Tracing, Logs, Metrics) 44.06 kB added added
CDN Bundle (incl. Replay, Logs, Metrics) 67.88 kB added added
CDN Bundle (incl. Tracing, Replay) 79.92 kB added added
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 80.83 kB added added
CDN Bundle (incl. Tracing, Replay, Feedback) 85.46 kB added added
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 86.39 kB added added
CDN Bundle - uncompressed 81.02 kB added added
CDN Bundle (incl. Tracing) - uncompressed 126.58 kB added added
CDN Bundle (incl. Logs, Metrics) - uncompressed 83.84 kB added added
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 129.4 kB added added
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 206.15 kB added added
CDN Bundle (incl. Tracing, Replay) - uncompressed 242.17 kB added added
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 244.99 kB added added
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 254.94 kB added added
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 257.76 kB added added
@sentry/nextjs (client) 47.37 kB added added
@sentry/sveltekit (client) 43.07 kB added added
@sentry/node-core 56.24 kB added added
@sentry/node 173.06 kB added added
@sentry/node - without tracing 96.25 kB added added
@sentry/aws-serverless 113.25 kB added added

@github-actions
Copy link
Contributor

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

Scenario Requests/s % of Baseline Prev. Requests/s Change %
GET Baseline 8,588 - - added
GET With Sentry 1,595 19% - added
GET With Sentry (error only) 5,860 68% - added
POST Baseline 1,167 - - added
POST With Sentry 562 48% - added
POST With Sentry (error only) 1,028 88% - added
MYSQL Baseline 3,196 - - added
MYSQL With Sentry 422 13% - added
MYSQL With Sentry (error only) 2,603 81% - added

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants