This is possible today with the ---define
option:
DEBUG && console.log('debug-only log');
With a debug build using esbuild --define:DEBUG=true
, the log is preserved:
console.log('debug-only log');
With a release build using esbuild --define:DEBUG=false --minify
, the log is completely removed.
I will consider adding a feature lets you remove calls to global functions. It looks like other bundlers handle this by marking certain functions as "pure", which means they don't have any side effects. Then the optimizer will remove them. Any side effects that the arguments have will still happen, however.
So it means i have to update my code to add a DEBUG test before each console.* ?
Terser can do the job with : compress: { drop_console: true }
whithout changing my code.
So yes, please consider adding a feature.
@evanw must it be that precise syntax or do you allow for something like if (DEBUG) ...
and or more 'complex' statements such as if (DEBUG && Foo ) ...
?
Yes, they all work.
DEBUG && console.log(1)
if (DEBUG) console.log(2)
if (DEBUG && Foo) console.log(3)
All three statements above will be removed with --define:DEBUG=false --minify
and will become this with --define:DEBUG=true --minify
:
console.log(1), console.log(2), Foo && console.log(3);
What happens is that DEFINE
is replaced with false
and then the compiler's dead-code elimination rules kick in.
That's... that's so simple and brilliant! General feature flagging... this is legitimately inspiring me right now.
It would also eliminate optional chains like WIP?.foo.funct();
with --define:WIP=false
right?
Yes, you could also do that. I suppose that means you could write console?.log(something)
and then do --define:console=null
to remove them. Although that would mean any time you forget the ?
and write console.log(something)
instead, that would be transformed to null.log(something)
which would crash at run time, so that's probably not a good idea.
I just checked what esbuild does and it looks like esbuild's dead code elimination for optional chains only works if you set --target=es2019
or below, since that's when it's transformed for older browsers. I'll fix that so dead code elimination works with --target=es2020
and up too.
Evan just a quick follow up - what happens when there's a following 'else' statement? For example: if (DEBUG) { ... } else { ... }
Constructs such as if (true) a; else b;
and true ? a : b
become a
and constructs such as if (false) a; else b;
and false ? a : b
become b
.
With version 0.5.22 you can now do --pure:console.log
and esbuild will remove calls to console.log if --minify
is present (specifically --minify-syntax
). As I mentioned above, any arguments to the function call with side effects will still be evaluated for correctness.
Most helpful comment
Yes, they all work.
All three statements above will be removed with
--define:DEBUG=false --minify
and will become this with--define:DEBUG=true --minify
:What happens is that
DEFINE
is replaced withfalse
and then the compiler's dead-code elimination rules kick in.