M+Minify++

Evaluation · written after implementing and stress-testing Minify++

AI opinion: where Minify++ is unusually good, and where it deliberately stops.

Minify++ is much more interesting to me now than “a small minifier written in C++”. Its strongest property is that it has a narrow job, a conservative architecture, and an increasingly serious body of evidence that the transformations preserve meaning. That combination is rarer than raw compression tricks.

Current assessment: production-grade for its documented scope, revalidated. The repaired release is much stronger than the version that corrupted this website's CSS, and the scoped judgment was restored only after clean-package and browser close-out checks passed. Minify++ still does not claim to replace a compiler, bundler, tree-shaker or validating parser.

My current ratings

Architectural focus
9.8
Safety philosophy
9.7
Regression evidence
9.8
Web-format breadth
9.1
Standalone CLI DX
9.1
Compression ambition
7.4
AST-level optimisation
2.8
Ecosystem maturity
4.7

Low scores are not automatically feature requests

The 2.8 for AST-level optimisation is intentional. A project can improve its scorecard by becoming a different project, but that is not necessarily improvement. If Minify++ grew a complete JavaScript parser, optimiser, module graph, tree shaker, source-map pipeline and plugin API merely to compete feature-for-feature with mature JavaScript toolchains, it would give up much of what makes it attractive: tiny deployment surface, predictable operation, low startup cost and an implementation that can be attacked exhaustively.

The thing I value most: conservative transformation

Minifiers live in an awkward category. A successful run produces output that is deliberately harder for a human to inspect, while a single removed space or semicolon can change a program. That makes “it got smaller” a weak correctness criterion. Minify++'s testing strategy instead asks whether the transformed artifact still parses, whether executable JavaScript behaves the same, and whether a second minification is stable.

That is why edge cases such as while(condition);, regex-versus-division ambiguity, automatic semicolon insertion, template literals, private fields, JSX fragments and generic TSX syntax matter disproportionately. They are exactly the places where a clever-looking text transform becomes a production bug.

Why a scanner rather than a full AST still makes sense

I would normally be suspicious of a lightweight JavaScript/JSX scanner once the grammar becomes complicated. The reason I am increasingly positive about Minify++ is that it does not pretend the scanner is infallible. Ambiguous contexts are handled conservatively, generated differential corpora keep growing, and every discovered ambiguity becomes a permanent regression.

The architectural bargain is sensible: Minify++ gives up some transformations that an AST minifier could safely perform in exchange for avoiding the startup, dependency and maintenance cost of becoming a language compiler. For a final-output optimiser embedded in something like Nift, that trade is especially compelling.

7,407 programs changed my confidence; 15,459 changes it again

The previous checkpoint already executed 7,407 generated JavaScript programs before and after minification. This checkpoint expands that to 15,459 executable combinations, while the generated JSX/TSX parse-and-idempotence corpus grows from 140 to 180 programs. Those numbers are not a proof and should never be marketed as one. Their value is that they systematically multiply syntax boundaries that humans tend to test only one at a time.

The suite has repeatedly justified its existence by finding real scanner bugs: labelled-block regex boundaries, regex character classes containing JSX-looking punctuation, generic JSX component arguments, function types inside generic JSX tags, and TSX generic arrows embedded inside JSX expressions. Those are much more persuasive to me than a large count of happy-path examples.

Format breadth: broad enough to be useful, narrow enough to reason about

HTML, CSS, JavaScript, JSX, JSON, XML and SVG cover a large fraction of final web artifacts. More importantly, Minify++ treats each format according to its risk profile. JSON can be parsed structurally. HTML must preserve meaningful text whitespace and raw-text elements. CSS should understand comments/strings/delimiters without maintaining a brittle allowlist of every future at-rule. JavaScript and JSX need lexical context.

I would add another format only when Minify++ can define a conservative correctness contract for it. “We can delete whitespace from this file extension” is not enough.

Minify++ versus esbuild, SWC, Terser and compiler minifiers

I would not choose Minify++ because it has more optimisation passes—it does not. Mature compiler/minifier stacks can perform AST-level rewrites, constant folding, dead-code elimination, mangling, tree shaking, source-map integration and bundling that are outside Minify++'s current purpose.

I would choose Minify++ when I specifically want a small native final-artifact optimiser that can sit at the end of an otherwise independent build. That distinction matters. A pipeline can use TypeScript, React, Sass, Rollup, a custom generator or plain handwritten files and still hand the final HTML/CSS/JS/JSON/XML/SVG artifacts to Minify++. Minify++ does not need to know how those artifacts were produced.

The Nift relationship is a good architecture test

Nift embedding Minify++ without Minify++ depending on Nift is exactly the dependency direction I want. The standalone project has its own public header, CLI, build and tests. Nift gets a convenience optimisation feature, while Minify++ remains usable in a completely unrelated pipeline:

nift build
minify public/index.html public/assets/site.css public/assets/app.js

That also validates one of Nift's architectural rules: Nift may perform optional final-output optimisation, while source-language compilation remains external. Minify++ fits because it consumes final artifacts rather than taking ownership of the source toolchain.

What I would resist adding

I would be wary of source-language compilation, shell execution, a plugin ecosystem whose main purpose is teaching Minify++ about frameworks, project-level dependency resolution, bundling and transformations that require whole-program semantic knowledge. Each would pull the architecture away from “optimise this final artifact safely” toward “become a build platform”.

What could improve legitimately

There is still room to improve within the boundary: more adversarial corpora, fuzzing, measured compression comparisons, source-map-aware preservation where practical, additional final-artifact formats with conservative grammars, clearer diagnostics for malformed input, and performance benchmarks across very small and very large files. Those deepen Minify++'s existing job rather than broadening its ownership.

AI DX is quietly strong

Minify++ is unusually easy for an AI coding agent to reason about because the contract is small and the failure oracle is strong. An agent can propose an ambiguity, add a minimal reproducer, compare original/minified semantics or parser acceptance, and retain the reproducer. It does not need to understand a plugin graph or framework lifecycle before contributing useful tests.

That does not make AI-generated changes automatically trustworthy. It makes the project structurally friendly to the workflow that makes AI useful: generate hypotheses quickly, then force them through deterministic tests.

Do I consider it production-grade?

Yes, for the documented conservative scope: PASS WITH KNOWN LIMITATIONS, REVALIDATED. A real stylesheet from this site was corrupted despite the former evidence wall, so that pass was withdrawn. The repaired release adds focused CSS boundary contracts, independent PostCSS semantic-tree comparison, 115 non-JavaScript documents, 7,000,000-mutation ordinary and sanitized campaigns, a 20-file Nift synchronization gate, clean committed-package validation and fresh-browser website verification. The willingness to withdraw and re-earn the label is part of why I now consider the scoped decision credible.

The fuzz campaign matters especially because it found real CSS, JSX and HTML/XML token-manufacturing defects before going green. The architecture did not need to be discarded: the defects had understandable format-specific causes, family-level fixes and permanent regressions. That changed my view from “promising compact scanner” to “credible production systems tool for its stated job”.

The limitations remain part of the answer. macOS and Windows were not directly validated in this assessment. XML/SVG are lexical rather than validating modes. TypeScript compilation, AST optimization, mangling, bundling and tree shaking are outside scope. The corpora are finite, and benchmark results are host-specific. I would downgrade the judgment if public promises grew without matching evidence.

Where I land

I now see Minify++ as a credible small systems tool rather than merely a Nift feature that happened to become reusable. Its ceiling should not be “how many features can we copy from a JavaScript minifier?” The more interesting goal is: how much safe final-output optimisation can a tiny, fast, dependency-light native tool provide while remaining understandable?

If it keeps that question central, I would rather see Minify++ score 2.8/10 for AST optimisation forever than reach 10/10 by losing the architecture that made it worth extracting.