Releases: evanw/esbuild
v0.8.42
-
Fix crash with block-level function declaration and
--keep-names
(#755)This release fixes a crash with block-level function declarations and the
--keep-names
option. The crash affected code that looks like this:if (true) function f() {} assert.strictEqual(f.name, 'f')
-
Disallow additional features in strict mode
This change improves esbuild's compliance with the JavaScript specification. It is now an error to use legacy octal numeric literals and the identifiers
implements
,interface
,let
,package
,private
,protected
,public
,static
, andyield
in strict mode code. -
Basic support for watch mode with plugins (#752)
With this release, watch mode should now work with simple on-load plugins. Watch mode is implemented by tracking all file system accesses made by esbuild as it does a build. However, this doesn't catch external file system accesses such as those made by plugins. Now if an on-load plugin is used on a path in the
file
namespace, esbuild will also read the file during watch mode so that watch mode is aware of the file system access. Note that there is not yet API support for a plugin to return additional paths for watch mode to monitor. -
Make JavaScript API error format more consistent (#745)
If a JavaScript error is thrown while validating the build options, the thrown error should now have
errors
andwarnings
properties just like normal build errors. Previously these properties were only present if the build itself failed but not if build options were invalid. This consistency should make it easier to process errors from the build API call.
v0.8.41
-
Fix memory leak with watch mode when using the CLI (#750)
This release fixes a memory leak when using
--watch
from the CLI (command-line interface). When esbuild was in this state, every incremental build resulted in more memory being consumed. This problem did not affect users of the JS API or Go API, only users of the CLI API.The problem was that the GC (garbage collector) was disabled. Oops. This is done by default for speed when you use esbuild via the CLI, which makes sense for most CLI use cases because the process is usually short-lived and doesn't need to waste time cleaning up memory. But it does not make sense for flags that cause esbuild to be a long-running process.
Previously the only exception to this rule was the
--serve
flag. When I added watch mode, I forgot to enable GC for the--watch
flag too. With this release, the GC is enabled for both the--serve
and the--watch
flags so esbuild should no longer leak memory in watch mode. -
Special-case certain syntax with
--format=esm
(#749)You can now no longer use the following syntax features with the
esm
output format:- The
with
statement:with (x) {}
- Delete of a bare identifier:
delete x
In addition, the following syntax feature is transformed when using the
esm
output format:- For-in variable initializers:
for (var x = y in {}) {}
→x = y; for (var x in {}) {}
The reason is because all JavaScript engines interpret code in the
esm
output format as strict mode and these syntax features are disallowed in strict mode. Note that this new strict mode handling behavior in esbuild is only dependent on the output format. It does not depend on the presence or absence of"use strict"
directives. - The
-
Basic
"use strict"
trackingThe JavaScript parser now tracks
"use strict"
directives and propagates strict mode status through the code. In addition, files containing theimport
and/orexport
keywords are also considered to be in strict mode. Strict mode handling is complex and esbuild currently doesn't implement all strict mode checks. But the changes in this release are a starting point. It is now an error to use certain syntax features such as awith
statement within a strict mode scope. -
Fix a minifier bug with
with
statementsThe minifier removes references to local variables if they are unused. However, that's not correct to do inside a
with
statement scope because what appears to be an identifier may actually be a property access, and property accesses could have arbitrary side effects if they resolve to a getter or setter method. Now all identifier expressions insidewith
statements are preserved when minifying. -
Transform block-level function declarations
Block-level function declarations are now transformed into equivalent syntax that avoids block-level declarations. Strict mode and non-strict mode have subtly incompatible behavior for how block-level function declarations are interpreted. Doing this transformation prevents problems with code that was originally strict mode that is run as non-strict mode and vice versa.
Now esbuild uses the presence or absence of a strict mode scope to determine how to interpret the block-level function declaration and then converts it to the equivalent unambiguous syntax such that it works the same regardless of whether or not the current scope is in strict mode:
// This original code: while (!y) { function y() {} } // is transformed into this code in strict mode: while (!y) { let y2 = function() {}; } // and into this code when not in strict mode: while (!y) { let y2 = function() {}; var y = y2; }
v0.8.40
-
Fix TypeScript parameter decorators on class constructors (#734)
This release fixes a TypeScript translation bug where parameter decorators on class constructors were translated incorrectly. Affected code looks like this:
class Example { constructor(@decorator param: any) {} }
This bug has been fixed. In addition, decorators are no longer allowed on class constructors themselves because they are not allowed in TypeScript.
-
Resolve
browser
entries inpackage.json
with no file extension (#740)This fix changes how esbuild interprets the
browser
field inpackage.json
. It will now remap imports without a file extension tobrowser
map entries without a file extension, which improves compatibility with Webpack. Specifically, apackage.json
file with"browser": {"./file": "./something.js"}
will now match an import of./file
. Previously thepackage.json
file had to contain something like"browser": {"./file.js": "./something.js"}
instead. Note that for compatibility with the rest of the ecosystem, a remapping of./file
will counter-intuitively not match an import of./file.js
even though it works fine in the other direction. -
Warning: npm v7 bug may prevent esbuild installation
This is a warning for people reading these release notes, not a code change. I have discovered a bug in npm v7 where your
package-lock.json
file can become corrupted such that nopostinstall
scripts are run. This bug affects all packages withpostinstall
scripts, not just esbuild, and happens when running npm v7 on apackage-lock.json
file from npm v6 or earlier. It seems like deleting and regenerating yourpackage-lock.json
file is a valid workaround that should get esbuild working again.
v0.8.39
-
Fix the JavaScript watch mode API exiting early (#730)
The previous release contained a bug that caused the JavaScript watch mode API to exit early in some cases. This bug should now be fixed. The problem was caused by some code that shouldn't even need to exist now that you are no longer required to call
stop()
on an esbuild service created bystartService()
(it was made optional in version 0.8.32). I took the opportunity to clean up the internals of esbuild's JavaScript API implementation which ended up removing the entire section of code that contained this bug. -
Add an API option for a per-build working directory (#689)
You can now use the
absWorkingDir
API option to customize the current working directory. It will default to the value ofprocess.cwd()
at the time of the call tostartService()
when not specified, which matches the existing behavior. The working directory is used for a few different things including resolving relative paths given as API options to absolute paths and pretty-printing absolute paths as relative paths in log messages.In addition to being a useful feature, this change also simplifies esbuild's internals. Previously esbuild had to maintain separate child processes if the current working directory was changed in between build API calls. Now esbuild will always reuse the same child process across all build API calls. The
stop()
call on thestartService()
API is also now a no-op (it doesn't do anything anymore) and thestartService()
API may be removed in future releases. -
Fix stray
esbuild
process afternode
exits (#643)I discovered that using esbuild's JavaScript incremental build API could result in the child
esbuild
process not exiting when the parentnode
process exits. This was due to a reference counting issue. The bug has been fixed so this shouldn't happen anymore.
v0.8.38
-
Implement a simple cross-platform watch mode (#21)
With this release, you can use the
--watch
flag to run esbuild in watch mode which watches the file system for changes and does an incremental build when something has changed. The watch mode implementation uses polling instead of OS-specific file system events for portability.Note that it is still possible to implement watch mode yourself using esbuild's incremental build API and a file watcher library of your choice if you don't want to use a polling-based approach. Also note that this watch mode feature is about improving developer convenience and does not have any effect on incremental build time (i.e. watch mode is not faster than other forms of incremental builds).
The new polling system is intended to use relatively little CPU vs. a traditional polling system that scans the whole directory tree at once. The file system is still scanned regularly but each scan only checks a random subset of your files to reduce CPU usage. This means a change to a file will be picked up soon after the change is made but not necessarily instantly. With the current heuristics, large projects should be completely scanned around every 2 seconds so in the worst case it could take up to 2 seconds for a change to be noticed. However, after a change has been noticed the change's path goes on a short list of recently changed paths which are checked on every scan, so further changes to recently changed files should be noticed almost instantly.
-
Add
pluginData
to pass data between plugins (#696)You can now return additional data from a plugin in the optional
pluginData
field and it will be passed to the next plugin that runs in the plugin chain. So if you return it from anonLoad
plugin, it will be passed to theonResolve
plugins for any imports in that file, and if you return it from anonResolve
plugin, an arbitrary one will be passed to theonLoad
plugin when it loads the file (it's arbitrary since the relationship is many-to-one). This is useful to pass data between different plugins without them having to coordinate directly.
v0.8.37
-
Improve ambiguous import handling (#723)
It is an error to try to import a name from a file where there are multiple matching exports due to multiple
export * from
statements from files which export that name. This release contains a few improvements to ambiguous import handling:-
This release fixes a bug where named export shadowing didn't work correctly with multiple levels of re-exports. A named export closer in the re-export chain is supposed to hide a named export deeper in the re-export chain without causing an ambiguous import. The bug caused this case to be incorrectly flagged as an error even though it should have been allowed. This case is now allowed without an error.
-
Previously the error message just said that there was an ambiguous import but didn't have any additional information. With this release, the error message also points out where the two different exports that have collided are in their original source files. Hopefully this should make it quicker to diagnose these types of issues.
-
Real JavaScript environments only treat ambiguous imports as an error if they are explicitly a named import. Using the
import * as
syntax and then accessing the ambiguous import with a property access results inundefined
instead of an error. Previously esbuild also treated this case as an error because it automatically rewrites star-import syntax to named-import syntax to improve tree shaking. With this release, this case is now treated as a warning instead of an error and the import will be automatically replaced with anundefined
literal in the bundled code.
-
-
Reuse automatically-generated temporary
*.node
files (#719)The previous change to hide the automatically-generated N-API native node extensions from Yarn 2 writes these
*.node
files to the system's temporary directory. A new one was being created on each run which is wasteful even though they are only a few kilobytes in size. With this release*.node
files will now be reused if they are already present in the system's temporary directory, so a new one is no longer created on each run. This fix was contributed by @kzc. -
Fix the serve API with
outfile
(#707)This release fixes a bug where the serve API did not work with the
outfile
setting. Using this setting with the serve API should now work fine. -
Warn about duplicate keys in object literals
Using a duplicate key in an object literal such as
{x: 1, x: 2}
is now a warning. This is allowed in JavaScript but results in subsequent keys overwriting the previous key. It's usually a copy/paste error and isn't ever useful so it's worth warning about. -
Avoid generating duplicate keys in JSON metadata
The
output
map that is generated when themetafile
feature is active could potentially have duplicate keys if thefile
loader is used, there are multiple entry points, and two or more entry points reference the same file. This is harmless because both keys mapped to the same value, but it's confusing and unnecessary. Duplicate keys are no longer present in the output map in this latest release. -
Make the JSON metafile structure match the type definitions (#726)
Previously
imports
and/orexports
could be missing from entries in theoutput
map in certain cases (specifically for source maps and files loaded with thefile
loader). This was problematic because the TypeScript type definitions for the metafile say that theimports
andexports
properties are non-optional. With this release, theimports
andexports
properties are now always present so the existing TypeScript type definitions are now accurate. -
Update from Go 1.15.5 to Go 1.15.7
The version of Go used to build the released binary executables on npm is now Go 1.15.7. This change shouldn't result in any visible changes to esbuild. It was only upgraded because the Go extension for the VSCode IDE now uses the official
gopls
Go language service and this extension wanted the latest version of Go.
v0.8.36
-
Fix an issue with writing large files to stdout using the WebAssembly executable
The previous release introduced a regression where large output files written to stdout were incorrectly truncated when using the WebAssembly
esbuild
command. This regression was due to a missing callback to the JavaScriptwrite()
function when called on the stdout stream. The regression has been fixed. -
Hide the N-API native node extensions from Yarn 2
The previous release introduced some very small (1-2kb)
*.node
native extensions to fix a bug with node failing to exit properly. However, this causes Yarn 2 to unzip the esbuild package, which is undesirable. This release puts these native node extensions inside JavaScript code instead to hide them from Yarn 2. The native extensions are written to a temporary file at run-time if necessary.
v0.8.35
-
Fix a commonly-missed corner case with
await
inside**
I recently discovered an interesting discussion about JavaScript syntax entitled "Most implementations seem to have missed that
await x ** 2
is not legal". Indeed esbuild has missed this, but this is not surprising because V8 has missed this as well and I usually test esbuild against V8 to test if esbuild is conformant with the JavaScript standard. Regardless, it sounds like the result of the discussion is that the specification should stay the same and implementations should be fixed. This release fixes this bug in esbuild's parser. The syntaxawait x ** 2
is no longer allowed and parentheses are now preserved for the syntax(await x) ** 2
. -
Allow namespaced names in JSX syntax (#702)
XML-style namespaced names with a
:
in the middle are a part of the JSX specification but they are explicitly unimplemented by React and TypeScript so esbuild doesn't currently support them. However, there was a user request to support this feature since it's part of the JSX specification and esbuild's JSX support can be used for non-React purposes. So this release now supports namespaced names in JSX expressions:let xml = <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> <rdf:Description rdf:ID="local-record"> <dc:title>Local Record</dc:title> </rdf:Description> </rdf:RDF>
This JSX expression is now transformed by esbuild to the following JavaScript:
let xml = React.createElement("rdf:RDF", { "xmlns:rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", "xmlns:dc": "http://purl.org/dc/elements/1.1/" }, React.createElement("rdf:Description", { "rdf:ID": "local-record" }, React.createElement("dc:title", null, "Local Record")));
Note that if you are trying to namespace your React components, this is not the feature to use. You should be using a
.
instead of a:
for namespacing your React components since.
resolves to a JavaScript property access. -
Fix
worker: false
in esbuild's browser-based JavaScript APIThe browser-based JavaScript API creates a web worker by default but this can be disabled by passing
worker: false
. When you do this the WebAssembly code is run in the current thread which will lock up the thread. This is mainly useful if you're calling the JavaScript API from within a web worker and you want to avoid creating another nested web worker.This option was unintentionally broken when the internal JavaScript web worker source code was moved from an inline function to a string in version 0.5.20. The regression has been fixed and the
worker: false
scenario now has test coverage. -
Fix absolute paths with the
esbuild-wasm
package on Windows (#687)The package
esbuild-wasm
has anesbuild
command implemented using WebAssembly instead of using native code. It uses node's WebAssembly implementation and calls methods on node'sfs
module to access the file system.Go's
path/filepath
module has a bug where Windows paths are interpreted as Unix paths when targeting WebAssembly: golang/go#43768. This causes multiple issues including absolute paths such asC:\path\to\file.js
being interpreted as relative paths (since they don't start with a/
) and being joined onto the end of other paths.To fix this, esbuild now does all of its own path handling instead of using Go's path handling code. The esbuild code base now contains a forked copy of
path/filepath
that can handle both Windows and Unix paths. The decision about which one to use is made at run-time. When targeting WebAssembly, the presence of theC:\
directory is used to determine if Windows-style paths should be used.With this release, it should now be possible to use Windows-style paths with esbuild's WebAssembly implementation on Windows.
-
Fix using stdin with the
esbuild-wasm
package on Windows (#687)Node has an old bug (nodejs/node#19831, nodejs/node#35997) where
fs.read
returns an EOF error at the end of stdin on Windows. This causes Go's WebAssembly implementation to panic when esbuild tries to read from stdin.The workaround was to manually check for this case and then ignore the error in this specific case. With this release, it should now be possible to pipe something to the
esbuild
command on Windows. -
Fix stdout and stderr not supporting Unicode in the
esbuild-wasm
package on Windows (#687)Node's
fs.write
API is broken when writing Unicode to stdout and stderr on Windows, and this will never be fixed: nodejs/node#24550. This is problematic for Go's WebAssembly implementation because it uses this API for writing to all file descriptors.The workaround is to manually intercept the file descriptors for stdout and stderr and redirect them to
process.stdout
andprocess.stderr
respectively. Passing Unicode text towrite()
on these objects instead of on thefs
API strangely works fine. So with this release, Unicode text should now display correctly when using esbuild's WebAssembly implementation on Windows (or at least, as correctly as the poor Unicode support in Windows Command Prompt allows). -
Add a hack for faster command-line execution for the WebAssembly module in certain cases
Node has an unfortunate bug where the node process is unnecessarily kept open while a WebAssembly module is being optimized: nodejs/node#36616. This means cases where running
esbuild
should take a few milliseconds can end up taking many seconds instead.The workaround is to force node to exit by ending the process early. This is done in one of two ways depending on the exit code. For non-zero exit codes (i.e. when there is a build error), the
esbuild
command now callsprocess.kill(process.pid)
to avoid the hang.For zero exit codes, the
esbuild
command now loads a N-API native node extension that calls the operating system'sexit(0)
function. This is done without requiringnode-gyp
by precompiling each supported platform and just including all of them in theesbuild-wasm
package since they are so small. If this hack doesn't work in certain cases, the process should exit anyway just potentially many seconds later. Currently the only supported platforms for this hack are 64-bit macOS, Windows, and Linux. -
Fix non-absolute paths with the
esbuild-wasm
package in the browser (#693)When using esbuild in the browser via WebAssembly, it was not possible to specify an non-absolute output path. Normally you can do this and esbuild will just convert it to an absolute path by resolving it as a relative path from the current working directory. However, Go's WebAssembly implementation has no current working directory so the conversion operation to an absolute path failed, causing esbuild's API to fail.
With this release, esbuild should now behave as if the current working directory is
/
in the browser. For example, this means calling thebuild()
API withoutfile: 'file.js'
should now generate an output file called/file.js
instead of causing an error.
v0.8.34
-
Fix a parser bug about suffix expressions after an arrow function body (#701)
The JavaScript parser incorrectly handled suffix expressions after a non-expression arrow function body. In practice, this came up when a semicolon was omitted from the end of an expression statement and the following expression could be considered a suffix expression:
x = () => {} (y)
This was incorrectly parsed as
(x = () => {})(y);
instead ofx = () => {}; y;
. With this release, this edge case should now be parsed correctly. -
Add new
neutral
platform to help text (#695)The new
--platform=neutral
API option that was added in the previous release was incorrectly not listed in the CLI help text for the platform feature. This omission has been fixed. The fix was contributed by @hardfist.
v0.8.33
-
Fix esbuild potentially exiting early during incremental rebuilds
The change in the previous release to make calling
stop()
optional caused a regression for incremental rebuilds where callingrebuild()
could potentially cause the process to exit early before the incremental rebuild is completed. This is because the implementation ofrebuild()
was missing a reference count to track that the service is now temporarily needed again. This omission was an oversight, and has now been fixed. -
Fix using the new
sourcesContent
option with the transform API (#682)Due to an oversight, the
sourcesContent: false
option that was added in version 0.8.27 didn't work with the JavaScript transform API. This was unintentional and has been fixed. This fix was contributed by @jschaf. -
Insert the object spread shim in constructor methods after the
super()
call (#678)This fixes an issue with the transform for object spread to older compile targets. Previously the following code would be transformed to code that crashes when run if the compile target is
es2017
or lower:class Derived extends Base { prop = null; constructor({ ...args }) { super(args); } }
This code was incorrectly compiled to something like this, which will throw
ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
:class Derived extends Base { constructor(_a) { __publicField(this, "prop", null); var args = __rest(_a, []); super(args); } }
With this release, it will now be compiled to something like this instead:
class Derived extends Base { constructor(_a) { var args = __rest(_a, []); super(args); __publicField(this, "prop", null); } }
-
Add the
--platform=neutral
API option (#674)There are currently two platform values:
browser
(the default) andnode
. These settings are a convenient way to configure multiple defaults for other API options for maximum compatibility. However, some users want to configure everything themselves so esbuild does not assume any platform-specific behavior. In this case you can now use--platform=neutral
to disable platform-specific default values. Note that this means if you want to use npm-style packages you will have to configure a main field yourself with something like--main-fields=main
. -
Provide minified and non-minified versions of in-browser API library (#616)
The in-browser JavaScript API libraries for esbuild are in the esbuild-wasm package. There are two:
esbuild-wasm/lib/browser.js
in UMD format andesbuild-wasm/esm/browser.js
in ESM format. Previously these were minified since they contain a large string of JavaScript that cannot be minified by other tools. Now they are no longer minified, and there are new minified versions available atesbuild-wasm/lib/browser.min.js
andesbuild-wasm/esm/browser.min.js
.