Releases: evanw/esbuild
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
.
v0.8.32
-
Calling
stop()
on the JavaScript API is now optional (#656)The JavaScript implementation of esbuild's API now calls
unref()
internally so node will now exit even if the internal long-lived esbuild process is still running. You should no longer need to explicitly callstop()
on the service returned bystartService()
, which simplifies service lifetime management. This feature was contributed by @SalvatorePreviti. -
Fix bug in metafile path generation (#662)
Certain import path metadata in the JSON file generated by the
--metafile
setting could be incorrect in scenarios with code splitting active and multiple entry points in different subdirectories. The incorrect paths referred to cross-chunk imports of other generated code splitting chunks and were incorrectly relative to the subdirectory inside the output directory instead of relative to the output directory itself. This issue has been fixed. -
Add
kind
to import paths in metafile JSON (#655)The
--metafile
flag generates build metadata in JSON format describing the input and output files in the build. Previously import path objects only had apath
property. With this release, they now also have akind
property that describes the way the file was imported. The value is a string that is equal to one of the following values:For JavaScript files:
import-statement
require-call
dynamic-import
require-resolve
For CSS files:
import-rule
url-token
-
Add support for TypeScript 4.2 syntax
Most of the new features included in the TypeScript 4.2 beta announcement are type system features that don't apply to esbuild. But there's one upcoming feature that adds new syntax:
abstract
construct signatures. They look like this:let Ctor: abstract new () => HasArea = Shape;
This new syntax can now be parsed by esbuild.
-
Add
detail
to errors and warnings (#654)Errors and warnings returned by the JavaScript and Go APIs now have a
detail
property which contains the original error. This is relevant if a custom JavaScript exception is thrown or a custom Goerror
is returned from inside a plugin callback. -
Disable code warnings inside
node_modules
directories even with plugins (#666)Some of the warnings that esbuild generates exist to point out suspicious looking code that is likely a bug. An example is
typeof x == 'null'
since thetypeof
operator never generates the stringnull
. Arguably these warnings belong in a linter instead of in esbuild since esbuild is a bundler, but I figured that some warnings about obviously broken code would still be helpful because many people don't run linters. It's part of my quest to improve software quality. And these warnings have caught real bugs in published code so they aren't meaningless. The warning must be considered very unlikely to be a false positive to be included.A change was added in version 0.7.4 to exclude files inside
node_modules
directories from these warnings. Even if the warnings flag a real bug, the warning is frustrating as a user because it's mostly non-actionable. The only resolution other than turning off warnings is to file an issue with the package, since code in published packages is immutable.However, since then the plugin API has been released and this behavior didn't apply if the import path was resolved by a plugin. It only applied if the import path was resolved by esbuild itself. That problem is fixed in this release. Now these warnings will be omitted from any file with
node_modules
in its path, even if the path originated from a plugin. -
Remove the warning about self-assignment (#666)
This warning was added in version 0.8.11 and warns about self-assignment such as
x = x
. The rationale is that this is likely a copy/paste error. However, it triggers too often for cross-compiled TypeScript code so the false positive rate is too high. The warning has now been removed. -
Disable constant folding for the
?:
operator when not minifying (#657)When minification is not enabled, the
?:
operator will now no longer be simplified if the condition evaluates totrue
orfalse
. This could result in slower builds in certain cases because esbuild may now scan more files unnecessarily during bundling. This change was made because of a user request.
v0.8.31
-
Fix minification issue from previous release (#648)
The minification optimization to omit certain
continue
andreturn
statements when it's implied by control flow in version 0.8.29 caused a regression when the branch condition uses a hoisted function:if (fn()) return; ... function fn() {}
In that case, transforming the code by inverting the condition and moving the following statements inside the branch is not valid because the function is no longer hoisted to above the branch condition. This release fixes the regression by avoiding this optimization in cases like this.
-
Add the option
--sourcemap=both
(#650)This new option puts the generated source map both an inline
//# sourceMappingURL=
data URL comment inside the output file and in an external file next to the output file. Using it is also possible with the transform API, which will cause it to return both an inline data URL comment in thecode
value and the source map JSON in themap
value. -
Tree-shake unused code with
--format=iife
(#639)When the output format is IIFE (which wraps the code in an immediately-invoked function expression), esbuild now assumes that it's safe to remove unused code. This is an assumption that esbuild always makes when bundling but that esbuild previously didn't make when not bundling. Now esbuild will remove code even when not bundling as long as the output format is IIFE.
This is only done for the IIFE output format because people are currently using the other formats to compile "partial modules", meaning they expect to be able to append code to esbuild's output and have that appended code be able to reference unused code inside esbuild's output. So it's not safe for esbuild to remove unused code in those cases. The IIFE output format wraps everything in a closure so unused code is not exposed to the module-level scope. Appended code will not be able to access unused code inside the closure so that means it's safe to remove.
v0.8.30
-
Fix
@jsx
and@jsxFrag
comments without trailing spacesThe
--jsx-factory
and--jsx-fragment
settings can be set on a per-file basis using// @jsx name
or// @jsxFrag name
comments. Comments of the form/* @jsx name */
or/* @jsxFrag name */
will also work. However, there was a bug where comments of the form/* @jsx name*/
or/* @jsxFrag name*/
(a multi-line comment without a trailing space at the end) did not work. This bug has been fixed, and you now no longer need a trailing space for multi-line comments. -
Minification improvements
-
The expression before a switch statement is now folded into the value. This means
fn(); switch (x) { ... }
turns intoswitch (fn(), x) { ... }
. -
Uses of
===
and!==
are converted to==
or!=
if the types of both sides can easily be statically determined. This means(x & 1) === 0
turns into(x & 1) == 0
. -
Equality comparisons are removed if both sides are boolean and one side is a constant. This means
!x === true
turns into!x
. -
Certain unary and binary operators are now removed if unused. This means
if (a() === b()) {}
turns intoa(), b();
. -
The comma operator is now extracted from certain expressions. This means
(a, b) + c
turns intoa, b + c
. -
Minification now takes advantage of the left-associativity of certain operators. This means
a && (b && c)
turns intoa && b && c
. -
Computed properties that are strings now become no longer computed. This means
{['a']: b}
turns into{a: b}
andclass { ['a'] = b }
turns intoclass { a = b }
. -
Repeated if-jump statements are now merged. This means
if (a) break; if (b) break;
turns intoif (a || b) break;
.
-
-
Fix issues with nested source maps (#638)
A nested source map happens when an input file has a valid
//# sourceMappingURL=
comment that points to a valid source map file. In that case, esbuild will read that source map and use it to map back to the original source code from the generated file. This only happens if you enable source map generation in esbuild via--sourcemap
. This release fixes the following issues:-
Generated source maps were incorrect when an input file had a nested source map and the input source map had more than one source file. This regression was introduced by an optimization in version 0.8.25 that parallelizes the generation of certain internal source map data structures. The index into the generated
sources
array was incorrectly incremented by 1 for every input file instead of by the number of sources in the input source map. This issue has been fixed and now has test coverage. -
Generated source maps were incorrect when an input file had a nested source map, the file starts with a local variable, the previous file ends with a local variable of that same type, and the input source map is missing a mapping at the start of the file. An optimization was added in version 0.7.18 that splices together local variable declarations from separate files when they end up adjacent to each other in the generated output file (i.e.
var a=0;var b=2;
becomesvar a=0,b=2;
whena
andb
are in separate files). The source map splicing was expecting a mapping at the start of the file and that isn't necessarily the case when using nested source maps. The optimization has been disabled for now to fix source map generation, and this specific case has test coverage.
-