You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
e1af0e Ignore stdio on Windows when not waiting for process
Previously, when using PowerShell on Windows to open URLs or files without the wait option, the parent Node.js process would not exit naturally. Users had to press Ctrl+C to terminate the script. This happened because PowerShell kept stdio streams open, preventing the parent process from exiting even though subprocess.unref() was called.
This tool appears to no longer be maintained, but more
importantly there are far fewer production dependencies now
than when first introduced, and all are known/trusted.
f29786 Migrate from mocha to Node.js native test runner
Includes coverage reports when using Node.js 22 onwards
c446d7 Docs: libvips manages its own thread pool (#4455)
3498eb Docs: partially-revert 3009957, fix link to glibc malloc tunables
300995 Docs: Add note about libvips thread pool sizing
### v0.27.2* Allow import path specifiers starting with `#/` ([#4361](https://redirect.github.com/evanw/esbuild/pull/4361))
Previously the specification for `package.json` disallowed import path specifiers starting with `#/`, but this restriction [has recently been relaxed](https://redirect.github.com/nodejs/node/pull/60864) and support for it is being added across the JavaScript ecosystem. One use case is using it for a wildcard pattern such as mapping `#/*` to `./src/*` (previously you had to use another character such as `#_*` instead, which was more confusing). There is some more context in [nodejs/node#49182](https://redirect.github.com/nodejs/node/issues/49182).
This change was contributed by [@​hybrist](https://redirect.github.com/hybrist).
Automatically add the -webkit-mask prefix (#4357, #4358)
This release automatically adds the -webkit- vendor prefix for the mask CSS shorthand property:
Additional minification of switch statements (#4176, #4359)
This release contains additional minification patterns for reducing switch statements. Here is an example:
// Original codeswitch(x){case0:
foo()breakcase1:
default:
bar()}// Old output (with --minify)switch(x){case0:foo();break;case1:default:bar()}// New output (with --minify)x===0?foo():bar();
Forbid using declarations inside switch clauses (#4323)
This is a rare change to remove something that was previously possible. The Explicit Resource Management proposal introduced using declarations. These were previously allowed inside case and default clauses in switch statements. This had well-defined semantics and was already widely implemented (by V8, SpiderMonkey, TypeScript, esbuild, and others). However, it was considered to be too confusing because of how scope works in switch statements, so it has been removed from the specification. This edge case will now be a syntax error. See tc39/proposal-explicit-resource-management#215 and rbuckton/ecma262#14 for details.
Here is an example of code that is no longer allowed:
This is not being released in one of esbuild's breaking change releases since this feature hasn't been finalized yet, and esbuild always tracks the current state of the specification (so esbuild's previous behavior was arguably incorrect).
This release fixes a bug with the bundler that happens when importing an ES module using require (which causes it to be wrapped) and there's a top-level var inside an if statement without being wrapped in a { ... } block (and a few other conditions). The bundling transform needed to hoist these var declarations outside of the lazy ES module wrapper for correctness. See the issue for details.
Fix minifier bug with for inside try inside label (#4351)
This fixes an old regression from version v0.21.4. Some code was introduced to move the label inside the try statement to address a problem with transforming labeled for await loops to avoid the await (the transformation involves converting the for await loop into a for loop and wrapping it in a try statement). However, it introduces problems for cross-compiled JVM code that uses all three of these features heavily. This release restricts this transform to only apply to for loops that esbuild itself generates internally as part of the for await transform. Here is an example of some affected code:
// Original code
d: {
e: {try{while(1){break d }}catch{break e;}}}// Old output (with --minify)
a:try{e:for(;;)break a}catch{break e}// New output (with --minify)
a:e:try{for(;;)break a}catch{break e}
Inline IIFEs containing a single expression (#4354)
Previously inlining of IIFEs (immediately-invoked function expressions) only worked if the body contained a single return statement. Now it should also work if the body contains a single expression statement instead:
// Original codeconstfoo=()=>{constcb=()=>{console.log(x())}returncb()}// Old output (with --minify)constfoo=()=>(()=>{console.log(x())})();// New output (with --minify)constfoo=()=>{console.log(x())};
The minifier now strips empty finally clauses (#4353)
This improvement means that finally clauses containing dead code can potentially cause the associated try statement to be removed from the output entirely in minified builds:
// Original codefunctionfoo(callback){if(DEBUG)stack.push(callback.name);try{callback();}finally{if(DEBUG)stack.pop();}}// Old output (with --minify --define:DEBUG=false)functionfoo(a){try{a()}finally{}}// New output (with --minify --define:DEBUG=false)functionfoo(a){a()}
Allow tree-shaking of the Symbol constructor
With this release, calling Symbol is now considered to be side-effect free when the argument is known to be a primitive value. This means esbuild can now tree-shake module-level symbol variables:
// Original codeconsta=Symbol('foo')constb=Symbol(bar)// Old output (with --tree-shaking=true)consta=Symbol("foo");constb=Symbol(bar);// New output (with --tree-shaking=true)constb=Symbol(bar);
### v0.27.0**This release deliberately contains backwards-incompatible changes.** To avoid automatically picking up releases like this, you should either be pinning the exact version of `esbuild` in your `package.json` file (recommended) or be using a version range syntax that only accepts patch upgrades such as `^0.26.0` or `~0.26.0`. See npm's documentation about [semver](https://docs.npmjs.com/cli/v6/using-npm/semver/) for more information.
With this release, esbuild's binary loader will now use the new Uint8Array.fromBase64 function unless it's unavailable in the configured target environment. If it's unavailable, esbuild's previous code for this will be used as a fallback. Note that this means you may now need to specify target when using this feature with Node (for example --target=node22) unless you're using Node v25+.
Update the Go compiler from v1.23.12 to v1.25.4 (#4208, #4311)
This raises the operating system requirements for running esbuild:
Linux: now requires a kernel version of 3.2 or later
GitHub and npm are recommending that maintainers for packages such as esbuild switch to trusted publishing. With this release, a VM on GitHub will now build and publish all of esbuild's packages to npm instead of me. In theory.
Unfortunately there isn't really a way to test that this works other than to do it live. So this release is that live test. Hopefully this release is uneventful and is exactly the same as the previous one (well, except for the green provenance attestation checkmark on npm that happens with trusted publishing).
### v0.25.12* Fix a minification regression with CSS media queries ([#4315](https://redirect.github.com/evanw/esbuild/issues/4315))
The previous release introduced support for parsing media queries which unintentionally introduced a regression with the removal of duplicate media rules during minification. Specifically the grammar for @​media <media-type> and <media-condition-without-or> { ... } was missing an equality check for the <media-condition-without-or> part, so rules with different suffix clauses in this position would incorrectly compare equal and be deduplicated. This release fixes the regression.
Update the list of known JavaScript globals (#4310)
This release updates esbuild's internal list of known JavaScript globals. These are globals that are known to not have side-effects when the property is accessed. For example, accessing the global Array property is considered to be side-effect free but accessing the global scrollY property can trigger a layout, which is a side-effect. This is used by esbuild's tree-shaking to safely remove unused code that is known to be side-effect free. This update adds the following global properties:
Note that this does not indicate that constructing any of these objects is side-effect free, just that accessing the identifier is side-effect free. For example, this now allows esbuild to tree-shake classes that extend from Iterator:
// This can now be tree-shaken by esbuild:classExampleIteratorextendsIterator{}
Add support for the new @​view-transition CSS rule (#4313)
With this release, esbuild now has improved support for pretty-printing and minifying the new @​view-transition rule (which esbuild was previously unaware of):
The new view transition feature provides a mechanism for creating animated transitions between documents in a multi-page app. You can read more about view transition rules here.
The CSS minifier will now remove rules whose selectors contain :is() and :where() as those selectors will never match. These selectors can currently be automatically generated by esbuild when you give esbuild nonsensical input such as the following:
/* Original code */div:before {
color: green;
&.foo {
color: red;
}
}
/* Old output (with --supported:nesting=false --minify) */div:before{color:green}:is().foo{color:red}
/* New output (with --supported:nesting=false --minify) */div:before{color:green}
This input is nonsensical because CSS nesting is (unfortunately) not supported inside of pseudo-elements such as :before. Currently esbuild generates a rule containing :is() in this case when you tell esbuild to transform nested CSS into non-nested CSS. I think it's reasonable to do that as it sort of helps explain what's going on (or at least indicates that something is wrong in the output). It shouldn't be present in minified code, however, so this release now strips it out.
### v0.25.11* Add support for `with { type: 'bytes' }` imports ([#4292](https://redirect.github.com/evanw/esbuild/issues/4292))
The import bytes proposal has reached stage 2.7 in the TC39 process, which means that although it isn't quite recommended for implementation, it's generally approved and ready for validation. Furthermore it has already been implemented by Deno and Webpack. So with this release, esbuild will also add support for this. It behaves exactly the same as esbuild's existing binary loader. Here's an example:
With this release, esbuild will now transform CSS media query range syntax into equivalent syntax using min-/max- prefixes for older browsers. For example, the following CSS:
will be transformed like this with a target such as --target=chrome100 (or more specifically with --supported:media-range=false if desired):
@​media (min-width: 640px) and (max-width: 960px) {
main {
display: flex;
}
}
### v0.25.10* Fix a panic in a minification edge case ([#4287](https://redirect.github.com/evanw/esbuild/issues/4287))
This release fixes a panic due to a null pointer that could happen when esbuild inlines a doubly-nested identity function and the final result is empty. It was fixed by emitting the value undefined in this case, which avoids the panic. This case must be rare since it hasn't come up until now. Here is an example of code that previously triggered the panic (which only happened when minifying):
When transforming nested CSS to non-nested CSS, esbuild is supposed to filter out pseudo-elements such as ::placeholder for correctness. The CSS nesting specification says the following:
The nesting selector cannot represent pseudo-elements (identical to the behavior of the ':is()' pseudo-class). We’d like to relax this restriction, but need to do so simultaneously for both ':is()' and '&', since they’re intentionally built on the same underlying mechanisms.
However, it seems like this behavior is different for nested at-rules such as @​supports, which do work with pseudo-elements. So this release modifies esbuild's behavior to now take that into account:
### v0.25.9* Better support building projects that use Yarn on Windows ([#3131](https://redirect.github.com/evanw/esbuild/issues/3131), [#3663](https://redirect.github.com/evanw/esbuild/issues/3663))
With this release, you can now use esbuild to bundle projects that use Yarn Plug'n'Play on Windows on drives other than the C: drive. The problem was as follows:
Yarn in Plug'n'Play mode on Windows stores its global module cache on the C: drive
Some developers put their projects on the D: drive
Yarn generates relative paths that use ../.. to get from the project directory to the cache directory
Windows-style paths don't support directory traversal between drives via .. (so D:\.. is just D:)
I didn't have access to a Windows machine for testing this edge case
Yarn works around this edge case by pretending Windows-style paths beginning with C:\ are actually Unix-style paths beginning with /C:/, so the ../.. path segments are able to navigate across drives inside Yarn's implementation. This was broken for a long time in esbuild but I finally got access to a Windows machine and was able to debug and fix this edge case. So you should now be able to bundle these projects with esbuild.
Preserve parentheses around function expressions (#4252)
The V8 JavaScript VM uses parentheses around function expressions as an optimization hint to immediately compile the function. Otherwise the function would be lazily-compiled, which has additional overhead if that function is always called immediately as lazy compilation involves parsing the function twice. You can read V8's blog post about this for more details.
Previously esbuild did not represent parentheses around functions in the AST so they were lost during compilation. With this change, esbuild will now preserve parentheses around function expressions when they are present in the original source code. This means these optimization hints will not be lost when bundling with esbuild. In addition, esbuild will now automatically add this optimization hint to immediately-invoked function expressions. Here's an example:
// Original codeconstfn0=()=>0constfn1=(()=>1)console.log(fn0,function(){returnfn1()}())// Old outputconstfn0=()=>0;constfn1=()=>1;console.log(fn0,function(){returnfn1();}());// New outputconstfn0=()=>0;constfn1=(()=>1);console.log(fn0,(function(){returnfn1();})());
Note that you do not want to wrap all function expressions in parentheses. This optimization hint should only be used for functions that are called on initial load. Using this hint for functions that are not called on initial load will unnecessarily delay the initial load. Again, see V8's blog post linked above for details.
This should have no effect on existing code as this version change does not change Go's operating system support. It may remove certain false positive reports (specifically CVE-2025-4674 and CVE-2025-47907) from vulnerability scanners that only detect which version of the Go compiler esbuild uses.
In HTML reporter, there's a new tab we call "Speedboard":
It shows you all your executed tests sorted by slowness,
and can help you understand where your test suite is taking longer than expected.
Take a look at yours - maybe you'll find some tests that are spending a longer time waiting than they should!
Chrome for Testing
Starting with this release, Playwright switches from Chromium, to using Chrome for Testing builds. Both headed and headless browsers are subject to this. Your tests should still be passing after upgrading to Playwright 1.57.
We're expecting no functional changes to come from this switch. The biggest change is the new icon and title in your toolbar.
If you still see an unexpected behaviour change, please file an issue.
On Arm64 Linux, Playwright continues to use Chromium.
Waiting for webserver output
testConfig.webServer added a wait field. Pass a regular expression, and Playwright will wait until the webserver logs match it.
import{defineConfig}from'@​playwright/test';exportdefaultdefineConfig({webServer: {command: 'npm run start',wait: {stdout: '/Listening on port (?<my_server_port>\\d+)/'},},});
If you include a named capture group into the expression, then Playwright will provide the capture group contents via environment variables:
This is not just useful for capturing varying ports of dev servers. You can also use it to wait for readiness of a service that doesn't expose an HTTP readiness check, but instead prints a readiness message to stdout or stderr.
Breaking Change
After 3 years of being deprecated, we removed Page#accessibility from our API. Please use other libraries such as Axe if you need to test page accessibility. See our Node.js guide for integration with Axe.
worker.on('console') event is emitted when JavaScript within the worker calls one of console API methods, e.g. console.log or console.dir. worker.waitForEvent() can be used to wait for it.
New option steps in locator.click() and locator.dragTo() that configures the number of mousemove events emitted while moving the mouse pointer to the target element.
Network requests issued by Service Workers are now reported and can be routed through the BrowserContext, only in Chromium. You can opt out using the PLAYWRIGHT_DISABLE_SERVICE_WORKER_NETWORK environment variable.
Console messages from Service Workers are dispatched through worker.on('console'). You can opt out of this using the PLAYWRIGHT_DISABLE_SERVICE_WORKER_CONSOLE environment variable.
Browser Versions
Chromium 143.0.7499.4
Mozilla Firefox 144.0.2
WebKit 26.0
### v1.56.1## Highlights
#37871 chore: allow local-network-access permission in chromium
#37891 fix(agents): remove workspaceFolder ref from vscode mcp
#37759 chore: rename agents to test agents
#37757 chore(mcp): fallback to cwd when resolving test config
Browser Versions
Chromium 141.0.7390.37
Mozilla Firefox 142.0.1
WebKit 26.0
### v1.56.0## Playwright Agents
Introducing Playwright Agents, three custom agent definitions designed to guide LLMs through the core process of building a Playwright test:
🎭 planner explores the app and produces a Markdown test plan
🎭 generator transforms the Markdown plan into the Playwright Test files
🎭 healer executes the test suite and automatically repairs failing tests
Run npx playwright init-agents with your client of choice to generate the latest agent definitions:
# Generate agent files for each agentic loop# Visual Studio Code
npx playwright init-agents --loop=vscode
# Claude Code
npx playwright init-agents --loop=claude
# opencode
npx playwright init-agents --loop=opencode
[!NOTE]
VS Code v1.105 (currently on the VS Code Insiders channel) is needed for the agentic experience in VS Code. It will become stable shortly, we are a bit ahead of times with this functionality!
This version was also tested against the following stable channels:
Google Chrome 139
Microsoft Edge 139
### v1.55.0## New APIs
New Property testStepInfo.titlePath Returns the full title path starting from the test file, including test and step titles.
Codegen
Automatic toBeVisible() assertions: Codegen can now generate automatic toBeVisible() assertions for common UI interactions. This feature can be enabled in the Codegen settings UI.
Breaking Changes
⚠️ Dropped support for Chromium extension manifest v2.
Miscellaneous
Added support for Debian 13 "Trixie".
Browser Versions
Chromium 140.0.7339.16
Mozilla Firefox 141.0
WebKit 26.0
This version was also tested against the following stable channels:
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Updated Packages