Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

--define with regex #163

Closed
hxhieu opened this issue May 31, 2020 · 10 comments
Closed

--define with regex #163

hxhieu opened this issue May 31, 2020 · 10 comments

Comments

@hxhieu
Copy link

hxhieu commented May 31, 2020

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

@evanw
Copy link
Owner

evanw commented Jun 1, 2020

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.

@hxhieu
Copy link
Author

hxhieu commented Jun 1, 2020

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?

@evanw
Copy link
Owner

evanw commented Jun 1, 2020

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.

@hxhieu
Copy link
Author

hxhieu commented Jun 1, 2020

Ah cool, thanks! I will try it out.

@kungfooman
Copy link

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.

@evanw
Copy link
Owner

evanw commented Jun 5, 2020

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.

@hxhieu hxhieu closed this as completed Jun 5, 2020
@evanw
Copy link
Owner

evanw commented Nov 12, 2020

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

@kungfooman
Copy link

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"

@evanw
Copy link
Owner

evanw commented Nov 13, 2020

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.

@Jarred-Sumner
Copy link
Contributor

Here is a plugin that adds support for //#ifdef: https://github.com/Jarred-Sumner/esbuild-plugin-ifdef

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants