Esbuild: Need option to remove console.*

Created on 20 Feb 2020  路  9Comments  路  Source: evanw/esbuild

Most helpful comment

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.

All 9 comments

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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

fannheyward picture fannheyward  路  4Comments

wcastand picture wcastand  路  4Comments

ayox picture ayox  路  4Comments

mohsen1 picture mohsen1  路  3Comments

lolychee picture lolychee  路  4Comments