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
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.
Most helpful comment
Ah, sorry. More detail:
--define:DEBUG=false
transformsif (DEBUG)
intoif (false)
. This then interacts with esbuild's dead code elimination, which is enabled when--minify
is provided (specifically the--minify-syntax
setting). All code insideif (false)
branches will not end up in the bundle when minifying.