Releases: evanw/esbuild
v0.8.47
-
Release native binaries for the Apple M1 chip (#550)
Previously installing esbuild on a M1 actually installed the x86-64 version, which required the Rosetta 2 translator. This was because Go hadn't yet released support for the M1. Now that Go 1.16.0 has been released, esbuild can support the M1 natively. It's supported by esbuild starting with this release. There are reports of the native version being 1.4x faster than the translated version. This change was contributed by @rtsao.
-
Omit warning about
require.someProperty
when targeting CommonJS (#812)The
require.cache
property allows introspecting the state of therequire
cache, generally without affecting what is imported/bundled.Since esbuild's static analyzer only detects direct calls to
require
, it currently warns about uses ofrequire
in any situation other than a direct call since that means the value is "escaping" the analyzer. This is meant to detect and warn about indirect calls such as['fs', 'path'].map(require)
.However, this warning is not relevant when accessing a property off of the
require
object such asrequire.cache
because a property access does not result in capturing the value ofrequire
. Now a warning is no longer generated forrequire.someProperty
when the output format iscjs
. This allows for the use of features such asrequire.cache
andrequire.extensions
. This fix was contributed by @huonw. -
Support ignored URL parameters at the end of import paths (#826)
If path resolution fails, ebuild will now try again with the URL query and/or fragment removed. This helps handle ancient CSS code like this that contains hacks for Internet Explorer:
@font-face { src: url("./themes/default/assets/fonts/icons.eot?#iefix") format('embedded-opentype'), url("./themes/default/assets/fonts/icons.woff2") format('woff2'), url("./themes/default/assets/fonts/icons.woff") format('woff'), url("./themes/default/assets/fonts/icons.ttf") format('truetype'), url("./themes/default/assets/fonts/icons.svg#icons") format('svg'); }
Previously path resolution would fail because these files do not end with the
.eot?#iefix
or.svg#icons
extensions. Now path resolution should succeed. The URL query and fragment are not unconditionally stripped because there is apparently code in the wild that uses#
as a directory name. So esbuild will still try to resolve the full import path first and only try to reinterpret the path as a URL if that fails. -
Prevent paths starting with
/
from being used as relative paths on Windows (#822)On Windows, absolute paths start with a drive letter such as
C:\...
instead of with a slash like/...
. This means that paths starting with a/
can actually be used as relative paths. For example, this means an import of/subfolder/image.png
will match the file at the path./subfolder/image.png
. This is problematic for Windows users because they may accidentally make use of these paths and then try to run their code on a non-Windows platform only for it to fail to build.Now paths starting with a
/
are always treated as an absolute path on all platforms. This means you can no longer import files at a relative path that starts with/
on Windows. You should be using a./
prefix instead. -
Warn when importing a path with the wrong case
Importing a path with the wrong case (e.g.
File.js
instead offile.js
) will work on Windows and sometimes on macOS because they have case-insensitive file systems, but it will never work on Linux because it has a case-sensitive file system. To help you make your code more portable and to avoid cross-platform build failures, esbuild now issues a warning when you do this.
v0.8.46
-
Fix minification of
.0
in CSS (#804)If you write
.0
instead of0
in CSS and enabled--minify
, esbuild would previously minify this token incorrectly (the token was deleted). This bug has been fixed and esbuild should now minify this token to0
. -
Support range requests in local HTTP server
The local HTTP server built in to esbuild now supports range requests, which are necessary for video playback in Safari. This means you can now use
<video>
tags in your HTML pages with esbuild's local HTTP server.
v0.8.45
-
Add the
--servedir=
flag (#796)The
--serve
flag starts a local web server and serves the files that would normally be written to the output directory. So for example if you had an entry point calledsrc/app.ts
and an output directory of--outdir=www/js
, using esbuild with--serve
would expose the generated output file via http://localhost:8000/app.js (but not write anything towww/js
). This can then be used in combination with your normal development server (running concurrently on another port) by adding<script src="http://localhost:8000/app.js"></script>
in your HTML file. So esbuild with the--serve
flag is meant to augment your normal development server, not replace it.This release introduces a new
--servedir=
flag which gives you the option of replacing your normal development server with esbuild. The directory you pass here will be "underlayed" below the output directory. Specifically when an incoming HTTP request comes in esbuild will first check if it matches one of the generated output files and if so, serve the output file directly from memory. Otherwise esbuild will fall back to serving content from the serve directory on the file system. In other words, server's URL structure behaves like a normal file server in a world where esbuild had written the generated output files to the file system (even though the output files actually only exist in memory).So for example if you had an entry point called
src/app.ts
and an output directory of--outdir=www/js
, using esbuild with--servedir=www
would expose the entire contents of thewww
directory via http://localhost:8000/ except for the http://localhost:8000/js/app.js URL which would contain the compiled contents ofsrc/app.ts
. This lets you have awww/index.html
file containing just<script src="/js/app.js"></script>
and use one web server instead of two.The benefit of doing things this way is that you can use the exact same HTML pages in development and production. In development you can run esbuild with
--servedir=
and esbuild will serve the generated output files directly. For production you can omit that flag and esbuild will write the generated files to the file system. In both cases you should be getting the exact same result in the browser with the exact same code in both development and production.This will of course not support all workflows, but that's intentional. This is designed to be a quality-of-life improvement for the simple case of building a small static website with some HTML, JavaScript, and CSS. More advanced setups may prefer to avoid the
--servedir=
feature and e.g. configure a NGINX reverse proxy to esbuild's local server to integrate esbuild into a larger existing development setup.One unintended consequence of this feature is that esbuild can now be used as a general local HTTP server via
esbuild --servedir=.
. Without any entry points, esbuild won't actually build anything and will just serve files like a normal web server. This isn't the intended use case but it could perhaps be a useful side effect of this feature. -
Remove absolute paths for disabled packages from source maps (#786)
This change is similar to the one from the previous release for disabled files, but it applies to package paths instead of relative paths. It's relevant when using packages that override dependencies with alternative packages using the
browser
field in theirpackage.json
file. Using relative paths instead of absolute paths fixes a determinism issue where build output was different on different systems. This fix was contributed by @eelco. -
Handle absolute paths in
tsconfig.json
(#792)Some automatically-generated
tsconfig.json
paths can have absolute paths in them. This is allowed by the TypeScript compiler (specifically in thepaths
andextends
fields). With this release, esbuild now supports absolute paths inpaths
andextends
too. -
Change the watch mode output format (#793)
Previously esbuild would print a "..." animation to the console while watch mode was scanning for changes. The intent of this was to a) not take up too much space in the terminal and b) show that esbuild's watch mode isn't frozen. Since the release I have gotten feedback that this isn't desirable. People want more feedback about what's happening and want to be able to run regexes over the stderr stream instead of using esbuild's actual API.
This release changes the output format for watch mode. Now esbuild will print
[watch] build started
when watch mode triggers a rebuild and[watch] build finished
when the rebuild is complete. Any build errors will be printed in between those two log messages.Note that this means esbuild's watch mode output is now more verbose, especially when there are frequent file changes. If you want to hide these new messages you can use
--log-level=
with a level other thaninfo
.
v0.8.44
-
Create a logo for esbuild (#61)
This release introduces a logo for esbuild:
Inspirations for the logo include:
-
The fast-forward symbol because esbuild is extremely fast and because one of esbuild's goals is to accelerate the evolution of the whole web tooling ecosystem.
-
The right-shift symbol because esbuild's production optimizations make your code smaller and because esbuild itself contains many low-level optimizations for speed.
Having a logo for esbuild should make it easier to include esbuild in lists of other tools since the other tools often all have logos.
-
-
Add support for node's
--preserve-symlinks
flag (#781)This release adds the
--preserve-symlinks
flag which behaves like the corresponding flag in node. Without the flag, esbuild and node will use the real path (after resolving symlinks) as the identity of a file. This means that a given file can only be instantiated once. With the flag, esbuild and node will use the original path (without resolving symlinks) as the identity of a file. This means that a given file can be instantiated multiple times, once for every symlink pointing to it. Each copy will have its own identity so the resulting bundle may contain duplicate files. This option is useful if your code relies on this flag in node (or theresolve.symlinks
setting in Webpack). -
Ignore a leading byte order mark (BOM) in CSS files (#776)
Some text editors insert a U+FEFF code point at the start of text files. This is a zero-width non-breaking space character. Using one at the start of a file is a convention which is meant to indicate that the contents of the file are UTF-8 encoded. When this is done, the character is called a byte order mark.
Unlike JavaScript, CSS does not treat U+FEFF as whitespace. It is treated as an identifier instead. This was causing esbuild to misinterpret files starting with a BOM as starting with an extra identifier, which could then cause the initial CSS rule in the file to be parsed incorrectly.
Now esbuild will skip over a BOM if it's present before beginning to parse CSS. This should prevent issues when working with these files.
-
Add message notes to the API
The internal logging system has the ability to attach additional notes to messages to provide more information. These show up as additional log messages in the terminal when using the command-line interface. Here is an example of a note:
> src/structs/RTree.js: warning: Duplicate key "compareMinX" in object literal 469 │ compareMinX: function (a, b) ╵ ~~~~~~~~~~~ src/structs/RTree.js: note: The original "compareMinX" is here 206 │ compareMinX: compareNodeMinX, ╵ ~~~~~~~~~~~
With this release, notes are also supported in the JS and Go APIs. This means you can now generate your own notes using plugins as well as inspect the notes generated by esbuild.
-
Add origin information to errors from plugins (#780)
Errors thrown during JavaScript plugin callback evaluation will now be annoated to show where that plugin callback was registered. That looks like this:
> example-plugin.js: error: [example-plugin] foo.bar is not a function 15 │ foo.bar(); ╵ ^ at ./example-plugin.js:15:13 at ./node_modules/esbuild/lib/main.js:750:34 example-plugin.js: note: This error came from the "onLoad" callback registered here 13 │ build.onLoad({ filter: /.*/ }, args => { ╵ ~~~~~~ at setup (./example-plugin.js:13:13) at handlePlugins (./node_modules/esbuild/lib/main.js:668:7)
This should make it easier to debug crashes in plugin code.
-
Fix a regression with the synchronous JavaScript API (#784)
In version 0.8.39, a change was made to avoid dangling esbuild processes when node exits abnormally. The change introduced a periodic ping between the child esbuild process and its host process. If the ping doesn't go through, the child process is able to detect that the host process is no longer there. Then it knows to exit since it's no longer being used.
This caused a problem with the synchronous JavaScript API calls which run the esbuild child process in a single-response mode. The ping message was interpreted as a second response and tripped up the message protocol. Pings are only useful for the asynchronous API calls. Running the pings during synchronous API calls was unintentional. With this release pings are no longer run for synchronous API calls so this regression should be fixed.
-
Remove absolute paths for disabled files from source maps (#785)
Files can be ignored (i.e. set to empty) using the
browser
field inpackage.json
. Specifically, you can set thebrowser
field to a map where the key is the module name and the value isfalse
. This is a convention followed by several bundlers including esbuild.Previously ignoring a file caused that file's path to appear as an absolute path in any generated source map. This is problematic because it means different source maps will be generated on different systems, since the absolute path contains system-specific directory information. Now esbuild will treat these paths the same way it treats other paths and will put a relative path in the source map.
v0.8.43
-
Support the
XDG_CACHE_HOME
environment variable (#757)On Linux, the install script for esbuild currently caches downloaded binary executables in
~/.cache/esbuild/bin
. This change means esbuild will now try installing to$XDG_CACHE_HOME/esbuild/bin
instead of theXDG_CACHE_HOME
environment variable exists. This allows you to customize the cache directory on Linux. The specification that definesXDG_CACHE_HOME
is here. -
Further improve constant folding of branches (#765)
At a high level, this release adds the following substitutions to improve constant folding and dead code elimination:
if (anything && falsyWithSideEffects)
→if (anything, falsyWithSideEffects)
if (anything || truthyWithSideEffects)
→if (anything, truthyWithSideEffects)
if (anything && truthyNoSideEffects)
→if (anything)
if (anything || falsyNoSideEffects)
→if (anything)
if (anything, truthyOrFalsy)
→anything; if (truthyOrFalsy)
And also these substitutions for unused expressions:
primitive == primitive
→primitive, primitive
typeof identifier
→ (remove entirely)
The actual substitutions are more complex since they are more comprehensive but they essentially result in this high-level behavior. Note that these substitutions are only done when minification is enabled.
-
Fix an edge case with CSS variable syntax (#760)
CSS variables are whitespace-sensitive even though other CSS syntax is mostly not whitespace sensitive. It is apparently common for this to cause problems with CSS tooling that pretty-prints and minifies CSS, including esbuild before this release. Some examples of issues with other tools include postcss/postcss#1404 and tailwindlabs/tailwindcss#2889. The issue affects code like this:
div { --some-var: ; some-decl: var(--some-var, ); }
It would be a change in semantics to minify this code to either
--some-var:;
orvar(--some-var,)
due to the whitespace significance of CSS variables, so such transformations are invalid. With this release, esbuild should now preserve whitespace in these two situations (CSS variable declarations and CSS variable references). -
Add support for recursive symlinks during path resolution (#766)
Previously recursive symlinks (a symlink that points to another symlink) were an unhandled case in the path resolution algorithm. Now these cases should be supported up to a depth of 256 symlinks. This means esbuild's path resolution should now work with multi-level
yarn link
scenarios. -
Fix subtle circular dependency issue (#758)
If esbuild is used to transform TypeScript to JavaScript without bundling (i.e. each file is transformed individually), the output format is CommonJS, and the original TypeScript code contains an import cycle where at least one of the links in the cycle is an
export * as
re-export statement, there could be certain situations where evaluating the transformed code results in an import beingundefined
. This is caused by the__esModule
marker being added after the call torequire()
for the first transformed re-export statement. The fix was to move the marker to before the first call torequire()
. The__esModule
marker is a convention from Babel that esbuild reuses which marks a module as being originally in the ECMAScript module format instead of the CommonJS module format. -
Add support for the
NODE_PATH
environment variableThis is a rarely-used feature of Node's module resolution algorithm. From the documentation:
If the
NODE_PATH
environment variable is set to a colon-delimited list of absolute paths, then Node.js will search those paths for modules if they are not found elsewhere.On Windows,
NODE_PATH
is delimited by semicolons (;
) instead of colons.The CLI takes the list of node paths from the value of the
NODE_PATH
environment variable, but the JS and Go APIs take the list as an array of strings instead (callednodePaths
in JS andNodePaths
in Go).
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.