esbuild icon indicating copy to clipboard operation
esbuild copied to clipboard

Inconsistent minify output caused by type import

Open aleclarson opened this issue 1 year ago • 4 comments

Even though importing a type won't affect the behavior of a bundle, it causes ESBuild to use a different identifier, resulting in inconsistent output.

Reproduction

The reproduction steps are listed here: https://github.com/aleclarson/repro/tree/esbuild/consistent-minify#readme

git clone https://github.com/aleclarson/repro -b esbuild/consistent-minify

aleclarson avatar Aug 15 '24 19:08 aleclarson

Just occurred to me that the Terser comparison is unnecessary. If I first compile the TypeScript to JavaScript, then minify after with a separate esbuild --minify command, the issue doesn't occur, of course, because there won't be a type import at the time of minification.

aleclarson avatar Aug 15 '24 20:08 aleclarson

I can see the difference in output (e.g. this vs. this). But this doesn't seem to be a bug. The two results are functionally equivalent so this doesn't indicate a correctness issue.

evanw avatar Aug 16 '24 03:08 evanw

It's only a bug if, like me, you're using the output to determine whether the implementation has actually changed (e.g. between a PR and its target branch). In my case, this is useful to bail out of a GitHub action early (e.g. avoid running benchmarks) if only the JSDoc was updated or whatever.

Anyway, fixing this issue is very low priority (on my end anyway), because the workaround of running esbuild.build() twice (once for bundling, then for minifying) works well enough.

aleclarson avatar Aug 16 '24 03:08 aleclarson

Even after switching to a two-step process of "bundle then minify", identifiers were not always deterministic despite unchanged code (but only in CI for some reason; specifically ubuntu-latest in a GitHub action).

Therefore, I wrote a function for deterministic identifiers: https://github.com/radashi-org/radashi/blob/9aa272cd666b4278ca5df186aa5f8dbeca451bde/scripts/benchmarks/src/normalizeIdentifiers.ts

aleclarson avatar Aug 20 '24 20:08 aleclarson

I'm closing this as I don't consider this to be a correctness issue. The minifier uses heuristics that attempt to generate minified names that compress better with gzip enabled by biasing the alphabet used for minified names toward characters that are present more often in the original source code (see the implementation for details). That way characters used in strings can be reused for identifier names using a potentially smaller encoding in the gzip stream. It's a little more complicated than that (the contents of comments, import paths, and certain symbols are excluded) but it's a heuristic and is intentionally designed for speed, and not for the kind of precision you're asking for.

evanw avatar Sep 22 '24 01:09 evanw

I ran into this same issue, so I'm leaving a comment though I agree that it's low priority at best. I was attempting to demonstrate that a PR introducing sweeping changes to the type system of a multi-bundle project does not change the output code, and therefore doesn't require testing, but found that certain bundles respond to certain type names (even if those types are unused) by changing the naming of variables in the minified code.

skondrashov avatar Jun 16 '25 14:06 skondrashov