chore(deps): update dependency esbuild to v0.15.10
This PR contains the following updates:
| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| esbuild | 0.14.42 -> 0.15.10 |
β Dependency Lookup Warnings β
Warnings were logged while processing this repo. Please check the Dependency Dashboard for more information.
Release Notes
evanw/esbuild
v0.15.10
-
Add support for node's "pattern trailers" syntax (#β2569)
After esbuild implemented node's
exportsfeature inpackage.json, node changed the feature to also allow text after*wildcards in patterns. Previously the*was required to be at the end of the pattern. It lets you do something like this:{ "exports": { "./features/*": "./features/*.js", "./features/*.js": "./features/*.js" } }With this release, esbuild now supports these types of patterns too.
-
Fix subpath imports with Yarn PnP (#β2545)
Node has a little-used feature called subpath imports which are package-internal imports that start with
#and that go through theimportsmap inpackage.json. Previously esbuild had a bug that caused esbuild to not handle these correctly in packages installed via Yarn's "Plug'n'Play" installation strategy. The problem was that subpath imports were being checked after Yarn PnP instead of before. This release reorders these checks, which should allow subpath imports to work in this case. -
Link from JS to CSS in the metafile (#β1861, #β2565)
When you import CSS into a bundled JS file, esbuild creates a parallel CSS bundle next to your JS bundle. So if
app.tsimports some CSS files and you bundle it, esbuild will give youapp.jsandapp.css. You would then add both<script src="app.js"></script>and<link href="app.css" rel="stylesheet">to your HTML to include everything in the page. This approach is more efficient than having esbuild insert additional JavaScript intoapp.jsthat downloads and includesapp.cssbecause it means the browser can download and parse both the CSS and the JS in parallel (and potentially apply the CSS before the JS has even finished downloading).However, sometimes it's difficult to generate the
<link>tag. One case is when you've added[hash]to the entry names setting to include a content hash in the file name. Then the file name will look something likeapp-GX7G2SBE.cssand may change across subsequent builds. You can tell esbuild to generate build metadata using themetafileAPI option but the metadata only tells you which generated JS bundle corresponds to a JS entry point (via theentryPointproperty), not which file corresponds to the associated CSS bundle. Working around this was hacky and involved string manipulation.This release adds the
cssBundleproperty to the metafile to make this easier. It's present on the metadata for the generated JS bundle and points to the associated CSS bundle. So to generate the HTML tags for a given JS entry point, you first find the output file with theentryPointyou are looking for (and put that in a<script>tag), then check for thecssBundleproperty to find the associated CSS bundle (and put that in a<link>tag).One thing to note is that there is deliberately no
jsBundleproperty mapping the other way because it's not a 1:1 relationship. Two JS bundles can share the same CSS bundle in the case where the associated CSS bundles have the same name and content. In that case there would be no one value for a hypotheticaljsBundleproperty to have.
v0.15.9
-
Fix an obscure npm package installation issue with
--omit=optional(#β2558)The previous release introduced a regression with
npm install esbuild --omit=optionalwhere the filenode_modules/.bin/esbuildwould no longer be present after installation. That could cause any package scripts which used theesbuildcommand to no longer work. This release fixes the regression sonode_modules/.bin/esbuildshould now be present again after installation. This regression only affected people installing esbuild usingnpmwith either the--omit=optionalor--no-optionalflag, which is a somewhat unusual situation.More details:
The reason for this regression is due to some obscure npm implementation details. Since the Go compiler doesn't support trivial cross-compiling on certain Android platforms, esbuild's installer installs a WebAssembly shim on those platforms instead. In the previous release I attempted to simplify esbuild's WebAssembly shims to depend on the
esbuild-wasmpackage instead of including another whole copy of the WebAssembly binary (to make publishing faster and to save on file system space after installation). However, both theesbuildpackage and theesbuild-wasmpackage provide a binary calledesbuildand it turns out that addingesbuild-wasmas a nested dependency of theesbuildpackage (specificallyesbuildoptionally depends on@esbuild/android-armwhich depends onesbuild-wasm) caused npm to be confused about whatnode_modules/.bin/esbuildis supposed to be.It's pretty strange and unexpected that disabling the installation of optional dependencies altogether would suddenly cause an optional dependency's dependency to conflict with the top-level package. What happens under the hood is that if
--omit=optionalis present, npm attempts to uninstall theesbuild-wasmnested dependency at the end ofnpm install(even though theesbuild-wasmpackage was never installed due to--omit=optional). This uninstallation causesnode_modules/.bin/esbuildto be deleted.After doing a full investigation, I discovered that npm's handling of the
.bindirectory is deliberately very brittle. When multiple packages in the dependency tree put something in.binwith the same name, the end result is non-deterministic/random. What you get in.binmight be from one package, from the other package, or might be missing entirely. The workaround suggested by npm is to just avoid having two packages that put something in.binwith the same name. So this was fixed by making the@esbuild/android-armandesbuild-android-64packages each include another whole copy of the WebAssembly binary, which works because these packages don't put anything in.bin.
v0.15.8
-
Fix JSX name collision edge case (#β2534)
Code generated by esbuild could have a name collision in the following edge case:
- The JSX transformation mode is set to
automatic, which causesimportstatements to be inserted - An element uses a
{...spread}followed by akey={...}, which uses the legacycreateElementfallback imported fromreact - Another import uses a name that ends with
reactsuch as@remix-run/react - The output format has been set to CommonJS so that
importstatements are converted into require calls
In this case, esbuild previously generated two variables with the same name
import_react, like this:var import_react = require("react"); var import_react2 = require("@​remix-run/react");That bug is fixed in this release. The code generated by esbuild no longer contains a name collision.
- The JSX transformation mode is set to
-
Fall back to WebAssembly on Android ARM (#β1556, #β1578, #β2335, #β2526)
Go's compiler supports trivial cross-compiling to almost all platforms without installing any additional software other than the Go compiler itself. This has made it very easy for esbuild to publish native binary executables for many platforms. However, it strangely doesn't support cross-compiling to Android ARM without installing the Android build tools.
So instead of publishing a native esbuild binary executable to npm, this release publishes a WebAssembly fallback build. This is essentially the same as the
esbuild-wasmpackage but it's installed automatically when you install theesbuildpackage on Android ARM. So packages that depend on theesbuildpackage should now work on Android ARM. This change has not yet been tested end-to-end because I don't have a 32-bit Android ARM device myself, but in theory it should work.This inherits the drawbacks of WebAssembly including significantly slower performance than native as well as potentially also more severe memory usage limitations and lack of certain features (e.g.
--serve). If you want to use a native binary executable of esbuild on Android ARM, you may be able to build it yourself from source after installing the Android build tools. -
Attempt to better support Yarn's
ignorePatternDatafeature (#β2495)Part of resolving paths in a project using Yarn's Plug'n'Play feature involves evaluating a regular expression in the
ignorePatternDataproperty of.pnp.data.json. However, it turns out that the particular regular expressions generated by Yarn use some syntax that works with JavaScript regular expressions but that does not work with Go regular expressions.In this release, esbuild will now strip some of the the problematic syntax from the regular expression before compiling it, which should hopefully allow it to be compiled by Go's regular expression engine. The specific character sequences that esbuild currently strips are as follows:
(?!\.)(?!(?:^|\/)\.)(?!\.{1,2}(?:\/|$))(?!(?:^|\/)\.{1,2}(?:\/|$))
These seem to be used by Yarn to avoid the
.and..path segments in the middle of relative paths. The removal of these character sequences seems relatively harmless in this case since esbuild shouldn't ever generate such path segments. This change should add support to esbuild for Yarn'spnpIgnorePatternsfeature. -
Fix non-determinism issue with legacy block-level function declarations and strict mode (#β2537)
When function declaration statements are nested inside a block in strict mode, they are supposed to only be available within that block's scope. But in "sloppy mode" (which is what non-strict mode is commonly called), they are supposed to be available within the whole function's scope:
// This returns 1 due to strict mode function test1() { 'use strict' function fn() { return 1 } if (true) { function fn() { return 2 } } return fn() } // This returns 2 due to sloppy mode function test2() { function fn() { return 1 } if (true) { function fn() { return 2 } } return fn() }To implement this, esbuild compiles these two functions differently to reflect their different semantics:
function test1() { "use strict"; function fn() { return 1; } if (true) { let fn2 = function() { return 2; }; } return fn(); } function test2() { function fn() { return 1; } if (true) { let fn2 = function() { return 2; }; var fn = fn2; } return fn(); }However, the compilation had a subtle bug where the automatically-generated function-level symbols for multible hoisted block-level function declarations in the same block a sloppy-mode context were generated in a random order if the output was in strict mode, which could be the case if TypeScript's
alwaysStrictsetting was set to true. This lead to non-determinism in the output as the minifier would randomly exchange the generated names for these symbols on different runs. This bug has been fixed by sorting the keys of the unordered map before iterating over them. -
Fix parsing of
@keyframeswith string identifiers (#β2555)Firefox supports
@keyframeswith string identifier names. Previously this was treated as a syntax error by esbuild as it doesn't work in any other browser. The specification allows for this however, so it's technically not a syntax error (even though it would be unwise to use this feature at the moment). There was also a bug where esbuild would remove the identifier name in this case as the syntax wasn't recognized.This release changes esbuild's parsing of
@keyframesto now consider this case to be an unrecognized CSS rule. That means it will be passed through unmodified (so you can now use esbuild to bundle this Firefox-specific CSS) but the CSS will not be pretty-printed or minified. I don't think it makes sense for esbuild to have special code to handle this Firefox-specific syntax at this time. This decision can be revisited in the future if other browsers add support for this feature. -
Add the
--jsx-side-effectsAPI option (#β2539, #β2546)By default esbuild assumes that JSX expressions are side-effect free, which means they are annoated with
/* @​__PURE__ */comments and are removed during bundling when they are unused. This follows the common use of JSX for virtual DOM and applies to the vast majority of JSX libraries. However, some people have written JSX libraries that don't have this property. JSX expressions can have arbitrary side effects and can't be removed. If you are using such a library, you can now pass--jsx-side-effectsto tell esbuild that JSX expressions have side effects so it won't remove them when they are unused.This feature was contributed by @βrtsao.
v0.15.7
-
Add
--watch=foreverto allow esbuild to never terminate (#β1511, #β1885)Currently using esbuild's watch mode via
--watchfrom the CLI will stop watching if stdin is closed. The rationale is that stdin is automatically closed by the OS when the parent process exits, so stopping watch mode when stdin is closed ensures that esbuild's watch mode doesn't keep running forever after the parent process has been closed. For example, it would be bad if you wrote a shell script that didesbuild --watch &to run esbuild's watch mode in the background, and every time you run the script it creates a newesbuildprocess that runs forever.However, there are cases when it makes sense for esbuild's watch mode to never exit. One such case is within a short-lived VM where the lifetime of all processes inside the VM is expected to be the lifetime of the VM. Previously you could easily do this by piping the output of a long-lived command into esbuild's stdin such as
sleep 999999999 | esbuild --watch &. However, this possibility often doesn't occur to people, and it also doesn't work on Windows. People also sometimes attempt to keep esbuild open by piping an infinite stream of data to esbuild such as withesbuild --watch </dev/zero &which causes esbuild to spin at 100% CPU. So with this release, esbuild now has a--watch=foreverflag that will not stop watch mode when stdin is closed. -
Work around
PATHwithoutnodein install script (#β2519)Some people install esbuild's npm package in an environment without the
nodecommand in theirPATH. This fails on Windows because esbuild's install script runs theesbuildcommand before exiting as a sanity check, and on Windows theesbuildcommand has to be a JavaScript file because of some internal details about how npm handles thebinfolder (specifically theesbuildcommand lacks the.exeextension, which is required on Windows). This release attempts to work around this problem by usingprocess.execPathinstead of"node"as the command for running node. In theory this means the installer can now still function on Windows if something is wrong withPATH.
v0.15.6
-
Lower
for awaitloops (#β1930)This release lowers
for awaitloops to the equivalentforloop containingawaitwhen esbuild is configured such thatfor awaitloops are unsupported. This transform still requires at least generator functions to be supported since esbuild's lowering ofawaitcurrently relies on generators. This new transformation is mostly modeled after what the TypeScript compiler does. Here's an example:async function f() { for await (let x of y) x() }The code above will now become the following code with
--target=es2017(omitting the code for the__forAwaithelper function):async function f() { try { for (var iter = __forAwait(y), more, temp, error; more = !(temp = await iter.next()).done; more = false) { let x = temp.value; x(); } } catch (temp) { error = [temp]; } finally { try { more && (temp = iter.return) && await temp.call(iter); } finally { if (error) throw error[0]; } } } -
Automatically fix invalid
supportedconfigurations (#β2497)The
--target=setting lets you tell esbuild to target a specific version of one or more JavaScript runtimes such aschrome80,node14and esbuild will restrict its output to only those features supported by all targeted JavaScript runtimes. More recently, esbuild introduced the--supported:setting that lets you override which features are supported on a per-feature basis. However, this now lets you configure nonsensical things such as--supported:async-await=false --supported:async-generator=true. Previously doing this could result in esbuild building successfully but producing invalid output.Starting with this release, esbuild will now attempt to automatically fix nonsensical feature override configurations by introducing more overrides until the configuration makes sense. So now the configuration from previous example will be changed such that
async-await=falseimpliesasync-generator=false. The full list of implications that were introduced is below:-
async-await=falseimplies:async-generator=falsefor-await=falsetop-level-await=false
-
generator=falseimplies:async-generator=false
-
object-accessors=falseimplies:class-private-accessor=falseclass-private-static-accessor=false
-
class-field=falseimplies:class-private-field=false
-
class-static-field=falseimplies:class-private-static-field=false
-
class=falseimplies:class-field=falseclass-private-accessor=falseclass-private-brand-check=falseclass-private-field=falseclass-private-method=falseclass-private-static-accessor=falseclass-private-static-field=falseclass-private-static-method=falseclass-static-blocks=falseclass-static-field=false
-
-
Implement a small minification improvement (#β2496)
Some people write code that contains a label with an immediate break such as
x: break x. Previously this code was not removed during minification but it will now be removed during minification starting with this release. -
Fix installing esbuild via Yarn with
enableScripts: falseconfigured (#β2457)If esbuild is installed with Yarn with the
enableScripts: falsesetting configured, then Yarn will not "unplug" theesbuildpackage (i.e. it will keep the entire package inside a.zipfile). This messes with esbuild's library code that extracts the platform-specific binary executable because that code copies the binary executable into the esbuild package directory, and Yarn's.zipfile system shim doesn't let you write to a directory inside of a.zipfile. This release fixes this problem by writing to thenode_modules/.cache/esbuilddirectory instead in this case. So you should now be able to use esbuild with Yarn whenenableScripts: falseis configured.This fix was contributed by @βjonaskuske.
v0.15.5
-
Fix issues with Yarn PnP and Yarn's workspaces feature (#β2476)
This release makes sure esbuild works with a Yarn feature called workspaces. Previously esbuild wasn't tested in this scenario, but this scenario now has test coverage. Getting this to work involved further tweaks to esbuild's custom code for what happens after Yarn PnP's path resolution algorithm runs, which is not currently covered by Yarn's PnP specification. These tweaks also fix
exportsmap resolution with Yarn PnP for non-empty subpaths, which wasn't previously working.
v0.15.4
-
Consider TypeScript import assignments to be side-effect free (#β2468)
TypeScript has a legacy import syntax for working with TypeScript namespaces that looks like this:
import { someNamespace } from './some-file' import bar = someNamespace.foo; // some-file.ts export namespace someNamespace { export let foo = 123 }Since esbuild converts TypeScript into JavaScript one file at a time, it doesn't know if
baris supposed to be a value or a type (or both, which TypeScript actually allows in this case). This is problematic because values are supposed to be kept during the conversion but types are supposed to be removed during the conversion. Currently esbuild keepsbarin the output, which is done becausesomeNamespace.foois a property access and property accesses run code that could potentially have a side effect (although there is no side effect in this case).With this release, esbuild will now consider
someNamespace.footo have no side effects. This meansbarwill now be removed when bundling and when tree shaking is enabled. Note that it will still not be removed when tree shaking is disabled. This is because in this mode, esbuild supports adding additional code to the end of the generated output that's in the same scope as the module. That code could potentially make use ofbar, so it would be incorrect to remove it. If you wantbarto be removed, you'll have to enable tree shaking (which tells esbuild that nothing else depends on the unexported top-level symbols in the generated output). -
Change the order of the banner and the
"use strict"directive (#β2467)Previously the top of the file contained the following things in order:
- The hashbang comment (see below) from the source code, if present
- The
"use strict"directive from the source code, if present - The content of esbuild's
bannerAPI option, if specified
This was problematic for people that used the
bannerAPI option to insert the hashbang comment instead of using esbuild's hashbang comment preservation feature. So with this release, the order has now been changed to:- The hashbang comment (see below) from the source code, if present
- The content of esbuild's
bannerAPI option, if specified - The
"use strict"directive from the source code, if present
I'm considering this change to be a bug fix instead of a breaking change because esbuild's documentation states that the
bannerAPI option can be used to "insert an arbitrary string at the beginning of generated JavaScript files". While this isn't technically true because esbuild may still insert the original hashbang comment before the banner, it's at least more correct now because the banner will now come before the"use strict"directive.For context: JavaScript files recently allowed using a hashbang comment, which starts with
#!and which must start at the very first character of the file. It allows Unix systems to execute the file directly as a script without needing to prefix it by thenodecommand. This comment typically has the value#!/usr/bin/env node. Hashbang comments will be a part of ES2023 when it's released next year. -
Fix
exportsmaps with Yarn PnP path resolution (#β2473)The Yarn PnP specification says that to resolve a package path, you first resolve it to the absolute path of a directory, and then you run node's module resolution algorithm on it. Previously esbuild followed this part of the specification. However, doing this means that
exportsinpackage.jsonis not respected because node's module resolution algorithm doesn't interpretexportsfor absolute paths. So with this release, esbuild will now use a modified algorithm that deviates from both specifications but that should hopefully behave more similar to what Yarn actually does: node's module resolution algorithm is run with the original import path but starting from the directory returned by Yarn PnP.
v0.15.3
-
Change the Yarn PnP manifest to a singleton (#β2463)
Previously esbuild searched for the Yarn PnP manifest in the parent directories of each file. But with Yarn's
enableGlobalCachesetting it's possible to configure Yarn PnP's implementation to reach outside of the directory subtree containing the Yarn PnP manifest. This was causing esbuild to fail to bundle projects with theenableGlobalCachesetting enabled.To handle this case, esbuild will now only search for the Yarn PnP manifest in the current working directory of the esbuild process. If you're using esbuild's CLI, this means you will now have to
cdinto the appropriate directory first. If you're using esbuild's API, you can override esbuild's value for the current working directory with theabsWorkingDirAPI option. -
Fix Yarn PnP resolution failures due to backslashes in paths on Windows (#β2462)
Previously dependencies of a Yarn PnP virtual dependency failed to resolve on Windows. This was because Windows uses
\instead of/as a path separator, and the path manipulation algorithms used for Yarn PnP expected/. This release converts\into/in Windows paths, which fixes this issue. -
Fix
sideEffectspatterns containing slashes on Windows (#β2465)The
sideEffectsfield inpackage.jsonlets you specify an array of patterns to mark which files have side effects (which causes all other files to be considered to not have side effects by exclusion). That looks like this:"sideEffects": [ "**/index.js", "**/index.prod.js" ]However, the presence of the
/character in the pattern meant that the pattern failed to match Windows-style paths, which brokesideEffectson Windows in this case. This release fixes this problem by adding additional code to handle Windows-style paths.
v0.15.2
-
Fix Yarn PnP issue with packages containing
index.js(#β2455, #β2461)Yarn PnP's tests require the resolved paths to end in
/. That's not how the rest of esbuild's internals work, however, and doing this messed up esbuild's node module path resolution regarding automatically-detectedindex.jsfiles. Previously packages that relied on implicitindex.jsresolution rules didn't work with esbuild under Yarn PnP. Removing this slash has fixed esbuild's path resolution behavior regardingindex.js, which should now the same both with and without Yarn PnP. -
Fix Yarn PnP support for
extendsintsconfig.json(#β2456)Previously using
extendsintsconfig.jsonwith a path in a Yarn PnP package didn't work. This is because the process of setting up package path resolution rules requires parsingtsconfig.jsonfiles (due to thebaseUrlandpathsfeatures) and resolvingextendsto a package path requires package path resolution rules to already be set up, which is a circular dependency. This cycle is broken by using special rules forextendsintsconfig.jsonthat bypasses esbuild's normal package path resolution process. This is why usingextendswith a Yarn PnP package didn't automatically work. With this release, these special rules have been modified to check for a Yarn PnP manifest so this case should work now. -
Fix Yarn PnP support in
esbuild-wasm(#β2458)When running esbuild via WebAssembly, Yarn PnP support previously failed because Go's file system internals return
EINVALwhen trying to read a.zipfile as a directory when run with WebAssembly. This was unexpected because Go's file system internals returnENOTDIRfor this case on native. This release updates esbuild to treatEINVALlikeENOTDIRin this case, which fixes usingesbuild-wasmto bundle a Yarn PnP project.Note that to be able to use
esbuild-wasmfor Yarn PnP successfully, you currently have to run it usingnodeinstead ofyarn node. This is because the file system shim that Yarn overwrites node's native file system API with currently generates invalid file descriptors with negative values when inside a.zipfile. This prevents esbuild from working correctly because Go's file system internals don't expect syscalls that succeed without an error to return an invalid file descriptor. Yarn is working on fixing their use of invalid file descriptors.
v0.15.1
-
Add support for node's "pattern trailers" syntax (#β2569)
After esbuild implemented node's
exportsfeature inpackage.json, node changed the feature to also allow text after*wildcards in patterns. Previously the*was required to be at the end of the pattern. It lets you do something like this:{ "exports": { "./features/*": "./features/*.js", "./features/*.js": "./features/*.js" } }With this release, esbuild now supports these types of patterns too.
-
Fix subpath imports with Yarn PnP (#β2545)
Node has a little-used feature called subpath imports which are package-internal imports that start with
#and that go through theimportsmap inpackage.json. Previously esbuild had a bug that caused esbuild to not handle these correctly in packages installed via Yarn's "Plug'n'Play" installation strategy. The problem was that subpath imports were being checked after Yarn PnP instead of before. This release reorders these checks, which should allow subpath imports to work in this case. -
Link from JS to CSS in the metafile (#β1861, #β2565)
When you import CSS into a bundled JS file, esbuild creates a parallel CSS bundle next to your JS bundle. So if
app.tsimports some CSS files and you bundle it, esbuild will give youapp.jsandapp.css. You would then add both<script src="app.js"></script>and<link href="app.css" rel="stylesheet">to your HTML to include everything in the page. This approach is more efficient than having esbuild insert additional JavaScript intoapp.jsthat downloads and includesapp.cssbecause it means the browser can download and parse both the CSS and the JS in parallel (and potentially apply the CSS before the JS has even finished downloading).However, sometimes it's difficult to generate the
<link>tag. One case is when you've added[hash]to the entry names setting to include a content hash in the file name. Then the file name will look something likeapp-GX7G2SBE.cssand may change across subsequent builds. You can tell esbuild to generate build metadata using themetafileAPI option but the metadata only tells you which generated JS bundle corresponds to a JS entry point (via theentryPointproperty), not which file corresponds to the associated CSS bundle. Working around this was hacky and involved string manipulation.This release adds the
cssBundleproperty to the metafile to make this easier. It's present on the metadata for the generated JS bundle and points to the associated CSS bundle. So to generate the HTML tags for a given JS entry point, you first find the output file with theentryPointyou are looking for (and put that in a<script>tag), then check for thecssBundleproperty to find the associated CSS bundle (and put that in a<link>tag).One thing to note is that there is deliberately no
jsBundleproperty mapping the other way because it's not a 1:1 relationship. Two JS bundles can share the same CSS bundle in the case where the associated CSS bundles have the same name and content. In that case there would be no one value for a hypotheticaljsBundleproperty to have.
v0.15.0
This release contains backwards-incompatible changes. Since esbuild is before version 1.0.0, these changes have been released as a new minor version to reflect this (as recommended by npm). You should either be pinning the exact version of esbuild in your package.json file or be using a version range syntax that only accepts patch upgrades such as ~0.14.0. See the documentation about semver for more information.
-
Implement the Yarn Plug'n'Play module resolution algorithm (#β154, #β237, #β1263, #β2451)
Node comes with a package manager called npm, which installs packages into a
node_modulesfolder. Node and esbuild both come with built-in rules for resolving import paths to packages withinnode_modules, so packages installed via npm work automatically without any configuration. However, many people use an alternative package manager called Yarn. While Yarn can install packages usingnode_modules, it also offers a different package installation strategy called Plug'n'Play, which is often shortened to "PnP" (not to be confused with pnpm, which is an entirely different unrelated package manager).Plug'n'Play installs packages as
.zipfiles on your file system. The packages are never actually unzipped. Since Node doesn't know anything about Yarn's package installation strategy, this means you can no longer run your code with Node as it won't be able to find your packages. Instead, you need to run your code with Yarn, which applies patches to Node's file system APIs before running your code. These patches attempt to make zip files seem like normal directories. When running under Yarn, using Node's file system API to read./some.zip/lib/file.jsactually automatically extractslib/file.jsfrom./some.zipat run-time as if it was a normal file. Other file system APIs behave similarly. However, these patches don't work with esbuild because esbuild is not written in JavaScript; it's a native binary executable that interacts with the file system directly through the operating system.Previously the workaround for using esbuild with Plug'n'Play was to use the
@yarnpkg/esbuild-plugin-pnpplugin with esbuild's JavaScript API. However, this wasn't great because the plugin needed to potentially intercept every single import path and file load to check whether it was a Plug'n'Play package, which has an unusually high performance cost. It also meant that certain subtleties of path resolution rules within a.zipfile could differ slightly from the way esbuild normally works since path resolution inside.zipfiles was implemented by Yarn, not by esbuild (which is due to a limitation of esbuild's plugin API).With this release, esbuild now contains an independent implementation of Yarn's Plug'n'Play algorithm (which is used when esbuild finds a
.pnp.js,.pnp.cjs, or.pnp.data.jsonfile in the directory tree). Creating additional implementations of this algorithm recently became possible because Yarn's package manifest format was recently documented: https://yarnpkg.com/advanced/pnp-spec/. This should mean that you can now use esbuild to bundle Plug'n'Play projects without any additional configuration (so you shouldn't need@yarnpkg/esbuild-plugin-pnpanymore). Bundling these projects should now happen much faster as Yarn no longer even needs to be run at all. Bundling the Yarn codebase itself with esbuild before and after this change seems to demonstrate over a 10x speedup (3.4s to 0.24s). And path resolution rules within Yarn packages should now be consistent with how esbuild handles regular Node packages. For example, fields such asmoduleandbrowserinpackage.jsonfiles within.zipfiles should now be respected.Keep in mind that this is brand new code and there may be some initial issues to work through before esbuild's implementation is solid. Yarn's Plug'n'Play specification is also brand new and may need some follow-up edits to guide new implementations to match Yarn's exact behavior. If you try this out, make sure to test it before committing to using it, and let me know if anything isn't working as expected. Should you need to debug esbuild's path resolution, you may find
--log-level=verbosehelpful.
v0.14.54
-
Fix optimizations for calls containing spread arguments (#β2445)
This release fixes the handling of spread arguments in the optimization of
/* @​__PURE__ */comments, empty functions, and identity functions:// Original code function empty() {} function identity(x) { return x } /* @​__PURE__ */ a(...x) /* @​__PURE__ */ new b(...x) empty(...x) identity(...x) // Old output (with --minify --tree-shaking=true) ...x;...x;...x;...x; // New output (with --minify --tree-shaking=true) function identity(n){return n}[...x];[...x];[...x];identity(...x);Previously esbuild assumed arguments with side effects could be directly inlined. This is almost always true except for spread arguments, which are not syntactically valid on their own and which have the side effect of causing iteration, which might have further side effects. Now esbuild will wrap these elements in an unused array so that they are syntactically valid and so that the iteration side effects are preserved.
v0.14.53
This release fixes a minor issue with the previous release: I had to rename the package esbuild-linux-loong64 to @esbuild/linux-loong64 in the contributed PR because someone registered the package name before I could claim it, and I missed a spot. Hopefully everything is working after this release. I plan to change all platform-specific package names to use the @esbuild/ scope at some point to avoid this problem in the future.
v0.14.52
-
Allow binary data as input to the JS
transformandbuildAPIs (#β2424)Previously esbuild's
transformandbuildAPIs could only take a string. However, some people want to use esbuild to convert binary data to base64 text. This is problematic because JavaScript strings represent UTF-16 text and esbuild internally operates on arrays of bytes, so all strings coming from JavaScript undergo UTF-16 to UTF-8 conversion before use. This meant that using esbuild in this way was doing base64 encoding of the UTF-8 encoding of the text, which was undesired.With this release, esbuild now accepts
Uint8Arrayin addition to string as an input format for thetransformandbuildAPIs. Now you can use esbuild to convert binary data to base64 text:// Original code import esbuild from 'esbuild' console.log([ (await esbuild.transform('\xFF', { loader: 'base64' })).code, (await esbuild.build({ stdin: { contents: '\xFF', loader: 'base64' }, write: false })).outputFiles[0].text, ]) console.log([ (await esbuild.transform(new Uint8Array([0xFF]), { loader: 'base64' })).code, (await esbuild.build({ stdin: { contents: new Uint8Array([0xFF]), loader: 'base64' }, write: false })).outputFiles[0].text, ]) // Old output [ 'module.exports = "w78=";\n', 'module.exports = "w78=";\n' ] /* ERROR: The input to "transform" must be a string */ // New output [ 'module.exports = "w78=";\n', 'module.exports = "w78=";\n' ] [ 'module.exports = "/w==";\n', 'module.exports = "/w==";\n' ] -
Update the getter for
textin build results (#β2423)Output files in build results returned from esbuild's JavaScript API have both a
contentsand atextproperty to return the contents of the output file. Thecontentsproperty is a binary UTF-8 Uint8Array and thetextproperty is a JavaScript UTF-16 string. Thetextproperty is a getter that does the UTF-8 to UTF-16 conversion only if it's needed for better performance.Previously if you mutate the build results object, you had to overwrite both
contentsandtextsince the value returned from thetextgetter is the original text returned by esbuild. Some people find this confusing so with this release, the getter fortexthas been updated to do the UTF-8 to UTF-16 conversion on the current value of thecontentsproperty instead of the original value. -
Publish builds for Linux LoongArch 64-bit (#β1804, #β2373)
This release upgrades to Go 1.19, which now includes support for LoongArch 64-bit processors. LoongArch 64-bit builds of esbuild will now be published to npm, which means that in theory they can now be installed with
npm install esbuild. This was contributed by @βbeyond-1234.
v0.14.51
-
Add support for React 17's
automaticJSX transform (#β334, #β718, #β1172, #β2318, #β2349)This adds support for the new "automatic" JSX runtime from React 17+ to esbuild for both the build and transform APIs.
New CLI flags and API options:
--jsx,jsxβ Set this to"automatic"to opt in to this new transform--jsx-dev,jsxDevβ Toggles development mode for the automatic runtime--jsx-import-source,jsxImportSourceβ Overrides the root import for runtime functions (default"react")
New JSX pragma comments:
@jsxRuntimeβ Sets the runtime (automaticorclassic)@jsxImportSourceβ Sets the import source (only valid with automatic runtime)
The existing
@jsxFragmentand@jsxFactorypragma comments are only valid with "classic" runtime.TSConfig resolving: Along with accepting the new options directly via CLI or API, option inference from
tsconfig.jsoncompiler options was also implemented:"jsx": "preserve"or"jsx": "react-native"β Same as--jsx=preservein esbuild"jsx": "react"β Same as--jsx=transformin esbuild (which is the default behavior)"jsx": "react-jsx"β Same as--jsx=automaticin esbuild"jsx": "react-jsxdev"β Same as--jsx=automatic --jsx-devin esbuild
It also reads the value of
"jsxImportSource"fromtsconfig.jsonif specified.For
react-jsxit's important to note that it doesn't implicitly disable--jsx-dev. This is to support the case where a user sets"react-jsx"in theirtsconfig.jsonbut then toggles development mode directly in esbuild.esbuild vs Babel vs TS vs...
There are a few differences between the various technologies that implement automatic JSX runtimes. The JSX transform in esbuild follows a mix of Babel's and TypeScript's behavior:
-
When an element has
__sourceor__selfprops:- Babel: Print an error about a deprecated transform plugin
- TypeScript: Allow the props
- swc: Hard crash
- esbuild: Print an error β Following Babel was chosen for this one because this might help people catch configuration issues where JSX files are being parsed by multiple tools
-
Element has an "implicit true" key prop, e.g.
<a key />:- Babel: Print an error indicating that "key" props require an explicit value
- TypeScript: Silently omit the "key" prop
- swc: Hard crash
- esbuild: Print an error like Babel β This might help catch legitimate programming mistakes
-
Element has spread children, e.g.
<a>{...children}</a>- Babel: Print an error stating that React doesn't support spread children
- TypeScript: Use static jsx function and pass children as-is, including spread operator
- swc: same as Babel
- esbuild: Same as TypeScript
Also note that TypeScript has some bugs regarding JSX development mode and the generation of
lineNumberandcolumnNumbervalues. Babel's values are accurate though, so esbuild's line and column numbers match Babel. Both numbers are 1-based and columns are counted in terms of UTF-16 code units.This feature was contributed by @βjgoz.
v0.14.50
-
Emit
namesin source maps (#β1296)The source map specification includes an optional
namesfield that can associate an identifier with a mapping entry. This can be used to record the original name for an identifier, which is useful if the identifier was renamed to something else in the generated code. When esbuild was originally written, this field wasn't widely used, but now there are some debuggers that make use of it to provide better debugging of minified code. With this release, esbuild now includes anamesfield in the source maps that it generates. To save space, the original name is only recorded when it's different from the final name. -
Update parser for arrow functions with initial default type parameters in
.tsxfiles (#β2410)TypeScript 4.6 introduced a change to the parsing of JSX syntax in
.tsxfiles. Now a<token followed by an identifier and then a=token is parsed as an arrow function with a default type parameter instead of as a JSX element. This release updates esbuild's parser to match TypeScript's parser. -
Fix an accidental infinite loop with
--definesubstitution (#β2407)This is a fix for a regression that was introduced in esbuild version 0.14.44 where certain
--definesubstitutions could result in esbuild crashing with a stack overflow. The problem was an incorrect fix for #β2292. The fix merged the code paths for--defineand--jsx-factoryrewriting since the value substitution is now the same for both. However, doing this accidentally made--definesubstitution recursive since the JSX factory needs to be able to match against--definesubstitutions to integrate with the--injectfeature. The fix is to only do one additional level of matching against define substitutions, and to only do this for JSX factories. Now these cases are able to build successfully without a stack overflow. -
Include the "public path" value in hashes (#β2403)
The
--public-path=configuration value affects the paths that esbuild uses to reference files from other files and is used in various situations such as cross-chunk imports in JS and references to asset files from CSS files. However, it wasn't included in the hash calculations used for file names due to an oversight. This meant that changing the public path setting incorrectly didn't result in the hashes in file names changing even though the contents of the files changed. This release fixes the issue by including a hash of the public path in all non-asset output files. -
Fix a cross-platform consistency bug (#β2383)
Previously esbuild would minify
0xFFFF_FFFF_FFFF_FFFFas0xffffffffffffffff(18 bytes) on arm64 chips and as18446744073709552e3(19 bytes) on x86_64 chips. The reason was that the number was converted to a 64-bit unsigned integer internally for printing as hexadecimal, the 64-bit floating-point number0xFFFF_FFFF_FFFF_FFFFis actually0x1_0000_0000_0000_0180(i.e. it's rounded up, not down), and convertingfloat64touint64is implementation-dependent in Go when the input is out of bounds. This was fixed by changing the upper limit for which esbuild uses hexadecimal numbers during minification to0xFFFF_FFFF_FFFF_F800, which is the next representable 64-bit floating-point number below0x1_0000_0000_0000_0180, and which fits in auint64. As a result, esbuild will now consistently never minify0xFFFF_FFFF_FFFF_FFFFas0xffffffffffffffffanymore, which means the output should now be consistent across platforms. -
Fix a hang with the synchronous API when the package is corrupted (#β2396)
An error message is already thrown when the esbuild package is corrupted and esbuild can't be run. However, if you are using a synchronous call in the JavaScript API in worker mode, esbuild will use a child worker to initialize esbuild once so that the overhead of initializing esbuild can be amortized across multiple synchronous API calls. However, errors thrown during initialization weren't being propagated correctly which resulted in a hang while the main thread waited forever for the child worker to finish initializing. With this release, initialization errors are now propagated correctly so calling a synchronous API call when the package is corrupted should now result in an error instead of a hang.
-
Fix
tsconfig.jsonfiles that collide with directory names (#β2411)TypeScript lets you write
tsconfig.jsonfiles withextendsclauses that refer to another config file using an implicit.jsonfile extension. However, if the config file without the.jsonextension existed as a directory name, esbuild and TypeScript had different behavior. TypeScript ignores the directory and continues looking for the config file by adding the.jsonextension while esbuild previously terminated the search and then failed to load the config file (because it's a directory). With this release, esbuild will now ignore exact matches when resolvingextendsfields intsconfig.jsonfiles if the exact match results in a directory. -
Add
platformto the transform API (#β2362)The
platformoption is mainly relevant for bundling because it mostly affects path resolution (e.g. activating the"browser"field inpackage.jsonfiles), so it was previously only available for the build API. With this release, it has additionally be made available for the transform API for a single reason: you can now set--platform=nodewhen transforming a string so that esbuild will add export annotations for node, which is only relevant when--format=cjsis also present.This has to do with an implementation detail of node that parses the AST of CommonJS files to discover named exports when importing CommonJS from ESM. However, this new addition to esbuild's API is of questionable usefulness. Node's loader API (the main use case for using esbuild's transform API like this) actually bypasses the content returned from the loader and parses the AST that's present on the file system, so you won't actually be able to use esbuild's API for this. See the linked issue for more information.
v0.14.49
-
Keep inlined constants when direct
evalis present (#β2361)Version 0.14.19 of esbuild added inlining of certain
constvariables during minification, which replaces all references to the variable with the initializer and then removes the variable declaration. However, this could generate incorrect code when directevalis present because the directevalcould reference the constant by name. This release fixes the problem by preserving theconstvariable declaration in this case:// Original code console.log((() => { const x = 123; return x + eval('x') })) // Old output (with --minify) console.log(()=>123+eval("x")); // New output (with --minify) console.log(()=>{const x=123;return 123+eval("x")}); -
Fix an incorrect error in TypeScript when targeting ES5 (#β2375)
Previously when compiling TypeScript code to ES5, esbuild could incorrectly consider the following syntax forms as a transformation error:
0 ? ([]) : 1 ? ({}) : 2;The error messages looked like this:
β [ERROR] Transforming destructurin
Configuration
π Schedule: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).
π¦ Automerge: Disabled due to failing status checks.
β» Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
π Ignore: Close this PR and you won't be reminded about this update again.
- [ ] If you want to rebase/retry this PR, click this checkbox.
This PR has been generated by Mend Renovate. View repository job log here.