JavaScript minifier
Strip comments and whitespace without renaming anything and without ever breaking automatic semicolon insertion. Smaller savings than Terser, and no way to silently change what your code does.
This minifier is deliberately conservative
It removes comments and whitespace. It does not rename variables, reorder anything, drop braces, shorten boolean literals or eliminate dead code. Everything it does is reversible by formatting the result, and nothing it does can change what your code means.
That is a real limitation and it is stated up front. A full minifier such as Terser typically gets a file 40 to 60 percent smaller; this gets 20 to 35. The difference is almost entirely variable renaming, which requires building a scope tree — and a scope tree built slightly wrong produces a bundle that is broken in a way you will not notice until production.
The thing it will not do to you
Automatic semicolon insertion is the reason naive JavaScript minifiers corrupt files. JavaScript ends a statement at a newline in some positions, so joining two lines can silently change the meaning rather than cause an error.
function get() {
return
{ ok: true }
}
// returns undefined — ASI put a semicolon after return
This minifier keeps a newline wherever removing it could matter. Specifically, it joins two lines only
when the first ends with a character that cannot end a statement — an opening brace, a comma, an operator —
or when the second begins with a character that cannot start one. After return,
throw, break, continue and yield, and after a closing
brace, the newline stays.
The result is a file with more line breaks than Terser would leave, and one that cannot break in this particular way.
The other thing that catches minifiers out
A forward slash starts a regular expression in some positions and divides in others, and the only way to tell is to look at what came before it.
const half = total / 2; // division
const valid = /^SAVE\d{2}$/; // regular expression
const odd = 1 / /x/.source.length; // both, on one line
Get this wrong and 1/ /x/ collapses to 1//x/, which turns the rest of the line
into a comment. The file still parses — it just does something else. That silent-corruption case is exactly
why this tokenises the input properly instead of using regular expressions on the text, and why strings,
template literals and comments are tracked rather than assumed.
What you actually save
| Stage | Typical script | Saving |
|---|---|---|
| Source, formatted and commented | 32.0 KB | — |
| This minifier | 23.5 KB | 27% |
| Terser, with renaming | 14.8 KB | 54% |
| Source + gzip | 8.9 KB | 72% |
| This minifier + gzip | 7.4 KB | 77% |
| Terser + gzip | 5.6 KB | 83% |
Illustrative figures, but the shape holds and it is the shape that matters. Compression does most of the work; minification adds to it; renaming adds more again. If your server is not compressing, fix that before anything else — it is one line of configuration and by far the biggest number in the table.
Comments
Comments are stripped by default, with one exception that every minifier makes: a block comment beginning
/*! is kept. That is the convention for licence headers, and several open-source licences
require the notice to survive into the distributed file.
Tick Keep comments to preserve all of them. Worth doing if you are minifying something you will need to read again, and pointless for anything going to production.
Doing it in a build
npx esbuild src/app.js --minify --outfile=dist/app.js
npx terser src/app.js --compress --mangle -o dist/app.js
# keep licence comments and generate a source map
npx terser src/app.js -c -m --comments "/^!/" --source-map -o dist/app.js
Vite, Next.js, Astro and every modern bundler minify in production builds already. Check before adding anything — you may be doing this twice, and minifying an already-minified file gains nothing.
Generate a source map whenever you minify for production. It costs nothing at runtime, it is only
downloaded when someone opens devtools, and it is the difference between debugging a real stack trace and
debugging a.b is not a function at line 1.
Questions about this tool
Why does the output still have line breaks?
Because removing them could change what the code does. JavaScript inserts semicolons at newlines in certain positions, so joining two lines is not always safe. This minifier keeps a newline wherever that applies — which is why it can promise never to alter behaviour.
Why does it not rename variables?
Renaming safely means building a complete scope tree, and handling eval, with, and property access by string. Getting it slightly wrong produces a bundle that breaks in production in a way that is very hard to trace. Terser does this properly and has been doing it for a decade — use it in a build.
Is the output safe to ship?
The transformations are conservative by design, and it is tested by minifying this site's own JavaScript and checking the result still behaves identically. As with any tool, test the minified file before you deploy it — that advice applies to Terser too.
Can I un-minify the result?
Yes — the formatter restores the indentation, and since nothing was renamed you get your variable names back too. Comments do not come back if you stripped them.
Does it work on a bundle from a framework?
It will run, and it will achieve almost nothing, because the bundle is already minified. Minifying twice is not additive. Minify your source, not your build output.
What about CSS and HTML inside the file?
Template literals are passed through byte for byte, so CSS-in-JS and HTML templates are untouched. If you want those compressed too, the CSS minifier and HTML minifier handle them on their own.
Related tools
Learn the why, not just the how
Longer reading on formatting, indentation and minification.