Esbuild: --define with regex

Created on 31 May 2020  路  9Comments  路  Source: evanw/esbuild

Hi,

Is there a way to replace a whole code block with --define?

So we have some blocks should only be in the debug build i.e console.log etc. They are delimited with a pair of comments

// #ifdef DEBUG
...
// #endif

I think if we could use a regex in --define then that would be it.

Or do you have any suggestion/workaround for our issue? Thanks

Most helpful comment

Ah, sorry. More detail: --define:DEBUG=false transforms if (DEBUG) into if (false). This then interacts with esbuild's dead code elimination, which is enabled when --minify is provided (specifically the --minify-syntax setting). All code inside if (false) branches will not end up in the bundle when minifying.

All 9 comments

I suggest using a normal if statement with a --define variable in the condition, like this:

if (DEBUG) {
  ... debug only code ...
}

Then debug builds can use --define:DEBUG=true and release builds can use --define:DEBUG=false.

If you aren't using esbuild for debug builds or don't want to pass --define:DEBUG=true for debug builds, you could also just ensure that window.DEBUG = true runs before the relevant code in debug builds.

Yeah that would work logic-wise but you know those comments are like C preprocessor so the code will be removed which results in a smaller bundle size. And some of us do care about the bundle size right?

Ah, sorry. More detail: --define:DEBUG=false transforms if (DEBUG) into if (false). This then interacts with esbuild's dead code elimination, which is enabled when --minify is provided (specifically the --minify-syntax setting). All code inside if (false) branches will not end up in the bundle when minifying.

Ah cool, thanks! I will try it out.

A C like preprocessor can't be replaced by JS logic:

Object.assign(pc, function () {
    // #ifdef DEBUG
    var _debugLogging = false;
    // #endif
            // #ifdef DEBUG
            try {
            // #endif
                script[method](arg);
            // #ifdef DEBUG
            } catch (ex) {
                // disable script if it fails to call method
                script.enabled = false;

                if (!script._callbacks || !script._callbacks.error) {
                    console.warn('unhandled exception while calling "' + method + '" for "' + script.__scriptType.__name + '" script: ', ex);
                    console.error(ex);
                }

                script.fire('error', ex, method);
                this.fire('error', script, ex, method);
            }
            // #endif

etc.

I'm not planning to build a preprocessor like that into esbuild because that's not part of the language. Cases like those will have to be addressed by running the preprocessor separately somehow. One way to do this might be plugins if those are eventually added. See #111.

FWIW this should be very possible to do with the plugin API now that it's been released.

I still don't see how that solves for macros in a usable way.

From the docs: If a plugin applies to every file in your build, then your build will likely be very slow. If caching is applicable, it must be done by the plugin itself.

So either esbuild will be very slow or every team has to compile their own Go build (while adding a new language to the tech stack)? A preprocessor seems kinda fundamental to me (and npm search results for preprocessors show ~30k weekly installations).

I guess it just boils down to "either esbuild supports it natively" or "sticking to other bundlers which are easy to extend via JS while not losing performance"

If a plugin applies to every file in your build, then your build will likely be very slow.

That warning was more for slow plugins like Babel that parse the code into an AST. If you can do #ifdef with simple string manipulation instead of an AST, it's likely going to be much faster than something like Babel. Also this plugin will be extra fast if the common case is one where the text #ifdef does not appear in the source code, because checking for that doesn't even require any parsing at all.

TL;DR: I think it can be pretty fast. I ran a simple JavaScript plugin that tests each file for the presence of #ifdef on a large private code base I have access to and it only slowed the build down by 0.2s. I'd recommend giving the plugin approach a try before dismissing it.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

elektronik2k5 picture elektronik2k5  路  3Comments

aelbore picture aelbore  路  4Comments

vforsh picture vforsh  路  3Comments

tonyhb picture tonyhb  路  3Comments

mohsen1 picture mohsen1  路  3Comments