Minification breaks code in a small number of predictable ways. Every one of these has bitten a production build somewhere, and every one has a fix that takes less time than the debugging session it prevents.
Almost always name mangling. Code that resolves things by identifier name — Angular's older DI syntax, anything reading Function.prototype.toString(), class names used as registry keys — breaks the moment UserService becomes e. Fix it by not depending on names: use explicit annotation arrays for DI, or a decorator. If you genuinely cannot, set keep_classnames: true and keep_fnames: true in Terser, accept the extra bytes, and add a comment explaining why.
Generate source maps and upload them to your error tracker rather than serving them. Build with --source-map and hidden references, then upload the .map files at deploy time so Sentry or your equivalent can symbolicate. Serving maps publicly ships your source; not generating them at all means every production error is e is not a function at column 44810.
Tree shaking removes exports it believes are unused. A module whose import you rely on purely for a side effect — a polyfill, a custom element registration, a CSS import — looks unused. The cause is usually a "sideEffects": false in package.json that is not actually true. List the real ones: "sideEffects": ["*.css", "./src/polyfills.js"].
CSS minifiers merge and reorder rules that they judge to be independent. When two selectors have equal specificity, source order decides the winner, and a merge can flip it. If a component only misstyles in production, disable rule merging and restructure so you are not relying on source order at all — that dependency is fragile with or without a minifier.
HTML minifiers collapse whitespace, which is correct everywhere except inside <pre>, <textarea> and elements with white-space: pre. Collapsing between inline elements also removes real spaces between words in some markup patterns. Configure the minifier to preserve those tags and check a rendered page rather than trusting a byte count.
Terser's unsafe compression family makes assumptions — that typeof x === 'undefined' can be rewritten, that array and object methods are not overridden, that Math is untouched. These are usually true and occasionally not, and when they are not the failure is silent. Leave the unsafe flags off; the byte saving is small and the debugging cost is not.
Minifiers strip comments, including licence headers that some dependencies legally require you to keep. Comments starting /*! are preserved by convention, and Terser's comments: 'some' keeps @license and @preserve annotations. Better still, extract them to a single LICENSES.txt served alongside the bundle.
Re-minifying a vendor .min.js adds build time and no bytes, and occasionally corrupts output that used a different mangling scheme. Exclude *.min.js from your minifier's inputs, and remember that after minification, Brotli compression does far more work than any further minifier setting — measure the compressed transfer size, not the raw file.