evanw/esbuild

Math is a side-effect

Opened this issue · 5 comments

constants with math operations are not being tree-shaken

INPUT

const FOO = 1 + 2

OUTPUT

// entry.js
var FOO = 1 + 2;

https://esbuild.github.io/try/#YgAwLjI0LjAALS1idW5kbGUgLS1mb3JtYXQ9ZXNtAGUAZW50cnkuanMAY29uc3QgRk9PID0gMSArIDI

Which in my case leaves a bunch of unused constants from imported but unused libraries.

// lib/memory.mjs
var REG_SIZE = 4;
var STRING_SIZE = 2 * REG_SIZE;

// vendor/pako/pako.js
var MIN_MATCH$1 = 3;
var MAX_MATCH$1 = 258;
var LENGTH_CODES$1 = 29;
var LITERALS$1 = 256;
var L_CODES$1 = LITERALS$1 + 1 + LENGTH_CODES$1;
var D_CODES$1 = 30;
var HEAP_SIZE$1 = 2 * L_CODES$1 + 1;
var static_ltree = /* @__PURE__ */ new Uint32Array((L_CODES$1 + 2) * 2);
var static_dtree = /* @__PURE__ */ new Uint32Array(D_CODES$1 * 2);
var _length_code = /* @__PURE__ */ new Uint32Array(MAX_MATCH$1 - MIN_MATCH$1 + 1);
var LENGTH_CODES = 29;
var LITERALS = 256;
var L_CODES = LITERALS + 1 + LENGTH_CODES;
var HEAP_SIZE = 2 * L_CODES + 1;
var MIN_MATCH = 3;
var MAX_MATCH = 258;
var MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1;

// site/git.ts
var UTF_0 = 0 + 48;
var UTF_1 = 1 + 48;
CODE

And there is no way to prevent this without making them to an iife afaik.

I that in fact it constant-folds and tree-shakes the first constant (in a file?) but does not continue doing that for subsequent constants.

In this playground

  • esbuild tree-shakes an unused constant with a literal number value
  • esbuild tree-shakes the first unused constant with arithmetic value
  • esbuild neither constant-folds nor tree-shakes the next two unused constants with arithmetic value

Bonus discovery - it works when the expression is +, - or all the bitwise operators I've tried.

It just fails for * and / !

Playground

@thetarnav Your playground works OK if you add --minify.

When minifying, esbuild will perform constant-folding, reducing your const FOO = 1 + 2 to const FOO = 3, and then that gets tree-shaken. Constant-folding doesn't happen unless minifying.

However, per my comments, this doesn't happen for * and / -- I wonder whether it should be reported as a separate bug?

My issue is mainly about --tree-shaking but thanks for letting me know that it disappears with --minify on. So yeah that would be a separate bug.

I think constant-folding even when --minify is passed does not happen for * and / because there might be no guarantees for loss of precision?