github.com/evanw/esbuild@v0.21.4/CHANGELOG-2023.md (about) 1 # Changelog: 2023 2 3 This changelog documents all esbuild versions published in the year 2023 (versions 0.16.13 through 0.19.11). 4 5 ## 0.19.11 6 7 * Fix TypeScript-specific class transform edge case ([#3559](https://github.com/evanw/esbuild/issues/3559)) 8 9 The previous release introduced an optimization that avoided transforming `super()` in the class constructor for TypeScript code compiled with `useDefineForClassFields` set to `false` if all class instance fields have no initializers. The rationale was that in this case, all class instance fields are omitted in the output so no changes to the constructor are needed. However, if all of this is the case _and_ there are `#private` instance fields with initializers, those private instance field initializers were still being moved into the constructor. This was problematic because they were being inserted before the call to `super()` (since `super()` is now no longer transformed in that case). This release introduces an additional optimization that avoids moving the private instance field initializers into the constructor in this edge case, which generates smaller code, matches the TypeScript compiler's output more closely, and avoids this bug: 10 11 ```ts 12 // Original code 13 class Foo extends Bar { 14 #private = 1; 15 public: any; 16 constructor() { 17 super(); 18 } 19 } 20 21 // Old output (with esbuild v0.19.9) 22 class Foo extends Bar { 23 constructor() { 24 super(); 25 this.#private = 1; 26 } 27 #private; 28 } 29 30 // Old output (with esbuild v0.19.10) 31 class Foo extends Bar { 32 constructor() { 33 this.#private = 1; 34 super(); 35 } 36 #private; 37 } 38 39 // New output 40 class Foo extends Bar { 41 #private = 1; 42 constructor() { 43 super(); 44 } 45 } 46 ``` 47 48 * Minifier: allow reording a primitive past a side-effect ([#3568](https://github.com/evanw/esbuild/issues/3568)) 49 50 The minifier previously allowed reordering a side-effect past a primitive, but didn't handle the case of reordering a primitive past a side-effect. This additional case is now handled: 51 52 ```js 53 // Original code 54 function f() { 55 let x = false; 56 let y = x; 57 const boolean = y; 58 let frag = $.template(`<p contenteditable="${boolean}">hello world</p>`); 59 return frag; 60 } 61 62 // Old output (with --minify) 63 function f(){const e=!1;return $.template(`<p contenteditable="${e}">hello world</p>`)} 64 65 // New output (with --minify) 66 function f(){return $.template('<p contenteditable="false">hello world</p>')} 67 ``` 68 69 * Minifier: consider properties named using known `Symbol` instances to be side-effect free ([#3561](https://github.com/evanw/esbuild/issues/3561)) 70 71 Many things in JavaScript can have side effects including property accesses and ToString operations, so using a symbol such as `Symbol.iterator` as a computed property name is not obviously side-effect free. This release adds a special case for known `Symbol` instances so that they are considered side-effect free when used as property names. For example, this class declaration will now be considered side-effect free: 72 73 ```js 74 class Foo { 75 *[Symbol.iterator]() { 76 } 77 } 78 ``` 79 80 * Provide the `stop()` API in node to exit esbuild's child process ([#3558](https://github.com/evanw/esbuild/issues/3558)) 81 82 You can now call `stop()` in esbuild's node API to exit esbuild's child process to reclaim the resources used. It only makes sense to do this for a long-lived node process when you know you will no longer be making any more esbuild API calls. It is not necessary to call this to allow node to exit, and it's advantageous to not call this in between calls to esbuild's API as sharing a single long-lived esbuild child process is more efficient than re-creating a new esbuild child process for every API call. This API call used to exist but was removed in [version 0.9.0](https://github.com/evanw/esbuild/releases/v0.9.0). This release adds it back due to a user request. 83 84 ## 0.19.10 85 86 * Fix glob imports in TypeScript files ([#3319](https://github.com/evanw/esbuild/issues/3319)) 87 88 This release fixes a problem where bundling a TypeScript file containing a glob import could emit a call to a helper function that doesn't exist. The problem happened because esbuild's TypeScript transformation removes unused imports (which is required for correctness, as they may be type-only imports) and esbuild's glob import transformation wasn't correctly marking the imported helper function as used. This wasn't caught earlier because most of esbuild's glob import tests were written in JavaScript, not in TypeScript. 89 90 * Fix `require()` glob imports with bundling disabled ([#3546](https://github.com/evanw/esbuild/issues/3546)) 91 92 Previously `require()` calls containing glob imports were incorrectly transformed when bundling was disabled. All glob imports should only be transformed when bundling is enabled. This bug has been fixed. 93 94 * Fix a panic when transforming optional chaining with `define` ([#3551](https://github.com/evanw/esbuild/issues/3551), [#3554](https://github.com/evanw/esbuild/pull/3554)) 95 96 This release fixes a case where esbuild could crash with a panic, which was triggered by using `define` to replace an expression containing an optional chain. Here is an example: 97 98 ```js 99 // Original code 100 console.log(process?.env.SHELL) 101 102 // Old output (with --define:process.env={}) 103 /* panic: Internal error (while parsing "<stdin>") */ 104 105 // New output (with --define:process.env={}) 106 var define_process_env_default = {}; 107 console.log(define_process_env_default.SHELL); 108 ``` 109 110 This fix was contributed by [@hi-ogawa](https://github.com/hi-ogawa). 111 112 * Work around a bug in node's CommonJS export name detector ([#3544](https://github.com/evanw/esbuild/issues/3544)) 113 114 The export names of a CommonJS module are dynamically-determined at run time because CommonJS exports are properties on a mutable object. But the export names of an ES module are statically-determined at module instantiation time by using `import` and `export` syntax and cannot be changed at run time. 115 116 When you import a CommonJS module into an ES module in node, node scans over the source code to attempt to detect the set of export names that the CommonJS module will end up using. That statically-determined set of names is used as the set of names that the ES module is allowed to import at module instantiation time. However, this scan appears to have bugs (or at least, can cause false positives) because it doesn't appear to do any scope analysis. Node will incorrectly consider the module to export something even if the assignment is done to a local variable instead of to the module-level `exports` object. For example: 117 118 ```js 119 // confuseNode.js 120 exports.confuseNode = function(exports) { 121 // If this local is called "exports", node incorrectly 122 // thinks this file has an export called "notAnExport". 123 exports.notAnExport = function() { 124 }; 125 }; 126 ``` 127 128 You can see that node incorrectly thinks the file `confuseNode.js` has an export called `notAnExport` when that file is loaded in an ES module context: 129 130 ```console 131 $ node -e 'import("./confuseNode.js").then(console.log)' 132 [Module: null prototype] { 133 confuseNode: [Function (anonymous)], 134 default: { confuseNode: [Function (anonymous)] }, 135 notAnExport: undefined 136 } 137 ``` 138 139 To avoid this, esbuild will now rename local variables that use the names `exports` and `module` when generating CommonJS output for the `node` platform. 140 141 * Fix the return value of esbuild's `super()` shim ([#3538](https://github.com/evanw/esbuild/issues/3538)) 142 143 Some people write `constructor` methods that use the return value of `super()` instead of using `this`. This isn't too common because [TypeScript doesn't let you do that](https://github.com/microsoft/TypeScript/issues/37847) but it can come up when writing JavaScript. Previously esbuild's class lowering transform incorrectly transformed the return value of `super()` into `undefined`. With this release, the return value of `super()` will now be `this` instead: 144 145 ```js 146 // Original code 147 class Foo extends Object { 148 field 149 constructor() { 150 console.log(typeof super()) 151 } 152 } 153 new Foo 154 155 // Old output (with --target=es6) 156 class Foo extends Object { 157 constructor() { 158 var __super = (...args) => { 159 super(...args); 160 __publicField(this, "field"); 161 }; 162 console.log(typeof __super()); 163 } 164 } 165 new Foo(); 166 167 // New output (with --target=es6) 168 class Foo extends Object { 169 constructor() { 170 var __super = (...args) => { 171 super(...args); 172 __publicField(this, "field"); 173 return this; 174 }; 175 console.log(typeof __super()); 176 } 177 } 178 new Foo(); 179 ``` 180 181 * Terminate the Go GC when esbuild's `stop()` API is called ([#3552](https://github.com/evanw/esbuild/issues/3552)) 182 183 If you use esbuild with WebAssembly and pass the `worker: false` flag to `esbuild.initialize()`, then esbuild will run the WebAssembly module on the main thread. If you do this within a Deno test and that test calls `esbuild.stop()` to clean up esbuild's resources, Deno may complain that a `setTimeout()` call lasted past the end of the test. This happens when the Go is in the middle of a garbage collection pass and has scheduled additional ongoing garbage collection work. Normally calling `esbuild.stop()` will terminate the web worker that the WebAssembly module runs in, which will terminate the Go GC, but that doesn't happen if you disable the web worker with `worker: false`. 184 185 With this release, esbuild will now attempt to terminate the Go GC in this edge case by calling `clearTimeout()` on these pending timeouts. 186 187 * Apply `/* @__NO_SIDE_EFFECTS__ */` on tagged template literals ([#3511](https://github.com/evanw/esbuild/issues/3511)) 188 189 Tagged template literals that reference functions annotated with a `@__NO_SIDE_EFFECTS__` comment are now able to be removed via tree-shaking if the result is unused. This is a convention from [Rollup](https://github.com/rollup/rollup/pull/5024). Here is an example: 190 191 ```js 192 // Original code 193 const html = /* @__NO_SIDE_EFFECTS__ */ (a, ...b) => ({ a, b }) 194 html`<a>remove</a>` 195 x = html`<b>keep</b>` 196 197 // Old output (with --tree-shaking=true) 198 const html = /* @__NO_SIDE_EFFECTS__ */ (a, ...b) => ({ a, b }); 199 html`<a>remove</a>`; 200 x = html`<b>keep</b>`; 201 202 // New output (with --tree-shaking=true) 203 const html = /* @__NO_SIDE_EFFECTS__ */ (a, ...b) => ({ a, b }); 204 x = html`<b>keep</b>`; 205 ``` 206 207 Note that this feature currently only works within a single file, so it's not especially useful. This feature does not yet work across separate files. I still recommend using `@__PURE__` annotations instead of this feature, as they have wider tooling support. The drawback of course is that `@__PURE__` annotations need to be added at each call site, not at the declaration, and for non-call expressions such as template literals you need to wrap the expression in an IIFE (immediately-invoked function expression) to create a call expression to apply the `@__PURE__` annotation to. 208 209 * Publish builds for IBM AIX PowerPC 64-bit ([#3549](https://github.com/evanw/esbuild/issues/3549)) 210 211 This release publishes a binary executable to npm for IBM AIX PowerPC 64-bit, which means that in theory esbuild can now be installed in that environment with `npm install esbuild`. This hasn't actually been tested yet. If you have access to such a system, it would be helpful to confirm whether or not doing this actually works. 212 213 ## 0.19.9 214 215 * Add support for transforming new CSS gradient syntax for older browsers 216 217 The specification called [CSS Images Module Level 4](https://www.w3.org/TR/css-images-4/) introduces new CSS gradient syntax for customizing how the browser interpolates colors in between color stops. You can now control the color space that the interpolation happens in as well as (for "polar" color spaces) control whether hue angle interpolation happens clockwise or counterclockwise. You can read more about this in [Mozilla's blog post about new CSS gradient features](https://developer.mozilla.org/en-US/blog/css-color-module-level-4/). 218 219 With this release, esbuild will now automatically transform this syntax for older browsers in the `target` list. For example, here's a gradient that should appear as a rainbow in a browser that supports this new syntax: 220 221 ```css 222 /* Original code */ 223 .rainbow-gradient { 224 width: 100px; 225 height: 100px; 226 background: linear-gradient(in hsl longer hue, #7ff, #77f); 227 } 228 229 /* New output (with --target=chrome99) */ 230 .rainbow-gradient { 231 width: 100px; 232 height: 100px; 233 background: 234 linear-gradient( 235 #77ffff, 236 #77ffaa 12.5%, 237 #77ff80 18.75%, 238 #84ff77 21.88%, 239 #99ff77 25%, 240 #eeff77 37.5%, 241 #fffb77 40.62%, 242 #ffe577 43.75%, 243 #ffbb77 50%, 244 #ff9077 56.25%, 245 #ff7b77 59.38%, 246 #ff7788 62.5%, 247 #ff77dd 75%, 248 #ff77f2 78.12%, 249 #f777ff 81.25%, 250 #cc77ff 87.5%, 251 #7777ff); 252 } 253 ``` 254 255 You can now use this syntax in your CSS source code and esbuild will automatically convert it to an equivalent gradient for older browsers. In addition, esbuild will now also transform "double position" and "transition hint" syntax for older browsers as appropriate: 256 257 ```css 258 /* Original code */ 259 .stripes { 260 width: 100px; 261 height: 100px; 262 background: linear-gradient(#e65 33%, #ff2 33% 67%, #99e 67%); 263 } 264 .glow { 265 width: 100px; 266 height: 100px; 267 background: radial-gradient(white 10%, 20%, black); 268 } 269 270 /* New output (with --target=chrome33) */ 271 .stripes { 272 width: 100px; 273 height: 100px; 274 background: 275 linear-gradient( 276 #e65 33%, 277 #ff2 33%, 278 #ff2 67%, 279 #99e 67%); 280 } 281 .glow { 282 width: 100px; 283 height: 100px; 284 background: 285 radial-gradient( 286 #ffffff 10%, 287 #aaaaaa 12.81%, 288 #959595 15.62%, 289 #7b7b7b 21.25%, 290 #5a5a5a 32.5%, 291 #444444 43.75%, 292 #323232 55%, 293 #161616 77.5%, 294 #000000); 295 } 296 ``` 297 298 You can see visual examples of these new syntax features by looking at [esbuild's gradient transformation tests](https://esbuild.github.io/gradient-tests/). 299 300 If necessary, esbuild will construct a new gradient that approximates the original gradient by recursively splitting the interval in between color stops until the approximation error is within a small threshold. That is why the above output CSS contains many more color stops than the input CSS. 301 302 Note that esbuild deliberately _replaces_ the original gradient with the approximation instead of inserting the approximation before the original gradient as a fallback. The latest version of Firefox has multiple gradient rendering bugs (including incorrect interpolation of partially-transparent colors and interpolating non-sRGB colors using the incorrect color space). If esbuild didn't replace the original gradient, then Firefox would use the original gradient instead of the fallback the appearance would be incorrect in Firefox. In other words, the latest version of Firefox supports modern gradient syntax but interprets it incorrectly. 303 304 * Add support for `color()`, `lab()`, `lch()`, `oklab()`, `oklch()`, and `hwb()` in CSS 305 306 CSS has recently added lots of new ways of specifying colors. You can read more about this in [Chrome's blog post about CSS color spaces](https://developer.chrome.com/docs/css-ui/high-definition-css-color-guide). 307 308 This release adds support for minifying colors that use the `color()`, `lab()`, `lch()`, `oklab()`, `oklch()`, or `hwb()` syntax and/or transforming these colors for browsers that don't support it yet: 309 310 ```css 311 /* Original code */ 312 div { 313 color: hwb(90deg 20% 40%); 314 background: color(display-p3 1 0 0); 315 } 316 317 /* New output (with --target=chrome99) */ 318 div { 319 color: #669933; 320 background: #ff0f0e; 321 background: color(display-p3 1 0 0); 322 } 323 ``` 324 325 As you can see, colors outside of the sRGB color space such as `color(display-p3 1 0 0)` are mapped back into the sRGB gamut and inserted as a fallback for browsers that don't support the new color syntax. 326 327 * Allow empty type parameter lists in certain cases ([#3512](https://github.com/evanw/esbuild/issues/3512)) 328 329 TypeScript allows interface declarations and type aliases to have empty type parameter lists. Previously esbuild didn't handle this edge case but with this release, esbuild will now parse this syntax: 330 331 ```ts 332 interface Foo<> {} 333 type Bar<> = {} 334 ``` 335 336 This fix was contributed by [@magic-akari](https://github.com/magic-akari). 337 338 ## 0.19.8 339 340 * Add a treemap chart to esbuild's bundle analyzer ([#2848](https://github.com/evanw/esbuild/issues/2848)) 341 342 The bundler analyzer on esbuild's website (https://esbuild.github.io/analyze/) now has a treemap chart type in addition to the two existing chart types (sunburst and flame). This should be more familiar for people coming from other similar tools, as well as make better use of large screens. 343 344 * Allow decorators after the `export` keyword ([#104](https://github.com/evanw/esbuild/issues/104)) 345 346 Previously esbuild's decorator parser followed the original behavior of TypeScript's experimental decorators feature, which only allowed decorators to come before the `export` keyword. However, the upcoming JavaScript decorators feature also allows decorators to come after the `export` keyword. And with TypeScript 5.0, TypeScript now also allows experimental decorators to come after the `export` keyword too. So esbuild now allows this as well: 347 348 ```js 349 // This old syntax has always been permitted: 350 @decorator export class Foo {} 351 @decorator export default class Foo {} 352 353 // This new syntax is now permitted too: 354 export @decorator class Foo {} 355 export default @decorator class Foo {} 356 ``` 357 358 In addition, esbuild's decorator parser has been rewritten to fix several subtle and likely unimportant edge cases with esbuild's parsing of exports and decorators in TypeScript (e.g. TypeScript apparently does automatic semicolon insertion after `interface` and `export interface` but not after `export default interface`). 359 360 * Pretty-print decorators using the same whitespace as the original 361 362 When printing code containing decorators, esbuild will now try to respect whether the original code contained newlines after the decorator or not. This can make generated code containing many decorators much more compact to read: 363 364 ```js 365 // Original code 366 class Foo { 367 @a @b @c abc 368 @x @y @z xyz 369 } 370 371 // Old output 372 class Foo { 373 @a 374 @b 375 @c 376 abc; 377 @x 378 @y 379 @z 380 xyz; 381 } 382 383 // New output 384 class Foo { 385 @a @b @c abc; 386 @x @y @z xyz; 387 } 388 ``` 389 390 ## 0.19.7 391 392 * Add support for bundling code that uses import attributes ([#3384](https://github.com/evanw/esbuild/issues/3384)) 393 394 JavaScript is gaining new syntax for associating a map of string key-value pairs with individual ESM imports. The proposal is still a work in progress and is still undergoing significant changes before being finalized. However, the first iteration has already been shipping in Chromium-based browsers for a while, and the second iteration has landed in V8 and is now shipping in node, so it makes sense for esbuild to support it. Here are the two major iterations of this proposal (so far): 395 396 1. Import assertions (deprecated, will not be standardized) 397 * Uses the `assert` keyword 398 * Does _not_ affect module resolution 399 * Causes an error if the assertion fails 400 * Shipping in Chrome 91+ (and in esbuild 0.11.22+) 401 402 2. Import attributes (currently set to become standardized) 403 * Uses the `with` keyword 404 * Affects module resolution 405 * Unknown attributes cause an error 406 * Shipping in node 21+ 407 408 You can already use esbuild to bundle code that uses import assertions (the first iteration). However, this feature is mostly useless for bundlers because import assertions are not allowed to affect module resolution. It's basically only useful as an annotation on external imports, which esbuild will then preserve in the output for use in a browser (which would otherwise refuse to load certain imports). 409 410 With this release, esbuild now supports bundling code that uses import attributes (the second iteration). This is much more useful for bundlers because they are allowed to affect module resolution, which means the key-value pairs can be provided to plugins. Here's an example, which uses esbuild's built-in support for the upcoming [JSON module standard](https://github.com/tc39/proposal-json-modules): 411 412 ```js 413 // On static imports 414 import foo from './package.json' with { type: 'json' } 415 console.log(foo) 416 417 // On dynamic imports 418 const bar = await import('./package.json', { with: { type: 'json' } }) 419 console.log(bar) 420 ``` 421 422 One important consequence of the change in semantics between import assertions and import attributes is that two imports with identical paths but different import attributes are now considered to be different modules. This is because the import attributes are provided to the loader, which might then use those attributes during loading. For example, you could imagine an image loader that produces an image of a different size depending on the import attributes. 423 424 Import attributes are now reported in the [metafile](https://esbuild.github.io/api/#metafile) and are now provided to [on-load plugins](https://esbuild.github.io/plugins/#on-load) as a map in the `with` property. For example, here's an esbuild plugin that turns all imports with a `type` import attribute equal to `'cheese'` into a module that exports the cheese emoji: 425 426 ```js 427 const cheesePlugin = { 428 name: 'cheese', 429 setup(build) { 430 build.onLoad({ filter: /.*/ }, args => { 431 if (args.with.type === 'cheese') return { 432 contents: `export default "š§"`, 433 } 434 }) 435 } 436 } 437 438 require('esbuild').build({ 439 bundle: true, 440 write: false, 441 stdin: { 442 contents: ` 443 import foo from 'data:text/javascript,' with { type: 'cheese' } 444 console.log(foo) 445 `, 446 }, 447 plugins: [cheesePlugin], 448 }).then(result => { 449 const code = new Function(result.outputFiles[0].text) 450 code() 451 }) 452 ``` 453 454 Warning: It's possible that the second iteration of this feature may change significantly again even though it's already shipping in real JavaScript VMs (since it has already happened once before). In that case, esbuild may end up adjusting its implementation to match the eventual standard behavior. So keep in mind that by using this, you are using an unstable upcoming JavaScript feature that may undergo breaking changes in the future. 455 456 * Adjust TypeScript experimental decorator behavior ([#3230](https://github.com/evanw/esbuild/issues/3230), [#3326](https://github.com/evanw/esbuild/issues/3326), [#3394](https://github.com/evanw/esbuild/issues/3394)) 457 458 With this release, esbuild will now allow TypeScript experimental decorators to access both static class properties and `#private` class names. For example: 459 460 ```js 461 const check = 462 <T,>(a: T, b: T): PropertyDecorator => 463 () => console.log(a === b) 464 465 async function test() { 466 class Foo { 467 static #foo = 1 468 static bar = 1 + Foo.#foo 469 @check(Foo.#foo, 1) a: any 470 @check(Foo.bar, await Promise.resolve(2)) b: any 471 } 472 } 473 474 test().then(() => console.log('pass')) 475 ``` 476 477 This will now print `true true pass` when compiled by esbuild. Previously esbuild evaluated TypeScript decorators outside of the class body, so it didn't allow decorators to access `Foo` or `#foo`. Now esbuild does something different, although it's hard to concisely explain exactly what esbuild is doing now (see the background section below for more information). 478 479 Note that TypeScript's experimental decorator support is currently buggy: TypeScript's compiler passes this test if only the first `@check` is present or if only the second `@check` is present, but TypeScript's compiler fails this test if both checks are present together. I haven't changed esbuild to match TypeScript's behavior exactly here because I'm waiting for TypeScript to fix these bugs instead. 480 481 Some background: TypeScript experimental decorators don't have consistent semantics regarding the context that the decorators are evaluated in. For example, TypeScript will let you use `await` within a decorator, which implies that the decorator runs outside the class body (since `await` isn't supported inside a class body), but TypeScript will also let you use `#private` names, which implies that the decorator runs inside the class body (since `#private` names are only supported inside a class body). The value of `this` in a decorator is also buggy (the run-time value of `this` changes if any decorator in the class uses a `#private` name but the type of `this` doesn't change, leading to the type checker no longer matching reality). These inconsistent semantics make it hard for esbuild to implement this feature as decorator evaluation happens in some superposition of both inside and outside the class body that is particular to the internal implementation details of the TypeScript compiler. 482 483 * Forbid `--keep-names` when targeting old browsers ([#3477](https://github.com/evanw/esbuild/issues/3477)) 484 485 The `--keep-names` setting needs to be able to assign to the `name` property on functions and classes. However, before ES6 this property was non-configurable, and attempting to assign to it would throw an error. So with this release, esbuild will no longer allow you to enable this setting while also targeting a really old browser. 486 487 ## 0.19.6 488 489 * Fix a constant folding bug with bigint equality 490 491 This release fixes a bug where esbuild incorrectly checked for bigint equality by checking the equality of the bigint literal text. This is correct if the bigint doesn't have a radix because bigint literals without a radix are always in canonical form (since leading zeros are not allowed). However, this is incorrect if the bigint has a radix (e.g. `0x123n`) because the canonical form is not enforced when a radix is present. 492 493 ```js 494 // Original code 495 console.log(!!0n, !!1n, 123n === 123n) 496 console.log(!!0x0n, !!0x1n, 123n === 0x7Bn) 497 498 // Old output 499 console.log(false, true, true); 500 console.log(true, true, false); 501 502 // New output 503 console.log(false, true, true); 504 console.log(!!0x0n, !!0x1n, 123n === 0x7Bn); 505 ``` 506 507 * Add some improvements to the JavaScript minifier 508 509 This release adds more cases to the JavaScript minifier, including support for inlining `String.fromCharCode` and `String.prototype.charCodeAt` when possible: 510 511 ```js 512 // Original code 513 document.onkeydown = e => e.keyCode === 'A'.charCodeAt(0) && console.log(String.fromCharCode(55358, 56768)) 514 515 // Old output (with --minify) 516 document.onkeydown=o=>o.keyCode==="A".charCodeAt(0)&&console.log(String.fromCharCode(55358,56768)); 517 518 // New output (with --minify) 519 document.onkeydown=o=>o.keyCode===65&&console.log("š§"); 520 ``` 521 522 In addition, immediately-invoked function expressions (IIFEs) that return a single expression are now inlined when minifying. This makes it possible to use IIFEs in combination with `@__PURE__` annotations to annotate arbitrary expressions as side-effect free without the IIFE wrapper impacting code size. For example: 523 524 ```js 525 // Original code 526 const sideEffectFreeOffset = /* @__PURE__ */ (() => computeSomething())() 527 use(sideEffectFreeOffset) 528 529 // Old output (with --minify) 530 const e=(()=>computeSomething())();use(e); 531 532 // New output (with --minify) 533 const e=computeSomething();use(e); 534 ``` 535 536 * Automatically prefix the `mask-composite` CSS property for WebKit ([#3493](https://github.com/evanw/esbuild/issues/3493)) 537 538 The `mask-composite` property will now be prefixed as `-webkit-mask-composite` for older WebKit-based browsers. In addition to prefixing the property name, handling older browsers also requires rewriting the values since WebKit uses non-standard names for the mask composite modes: 539 540 ```css 541 /* Original code */ 542 div { 543 mask-composite: add, subtract, intersect, exclude; 544 } 545 546 /* New output (with --target=chrome100) */ 547 div { 548 -webkit-mask-composite: 549 source-over, 550 source-out, 551 source-in, 552 xor; 553 mask-composite: 554 add, 555 subtract, 556 intersect, 557 exclude; 558 } 559 ``` 560 561 * Avoid referencing `this` from JSX elements in derived class constructors ([#3454](https://github.com/evanw/esbuild/issues/3454)) 562 563 When you enable `--jsx=automatic` and `--jsx-dev`, the JSX transform is supposed to insert `this` as the last argument to the `jsxDEV` function. I'm not sure exactly why this is and I can't find any specification for it, but in any case this causes the generated code to crash when you use a JSX element in a derived class constructor before the call to `super()` as `this` is not allowed to be accessed at that point. For example 564 565 ```js 566 // Original code 567 class ChildComponent extends ParentComponent { 568 constructor() { 569 super(<div />) 570 } 571 } 572 573 // Problematic output (with --loader=jsx --jsx=automatic --jsx-dev) 574 import { jsxDEV } from "react/jsx-dev-runtime"; 575 class ChildComponent extends ParentComponent { 576 constructor() { 577 super(/* @__PURE__ */ jsxDEV("div", {}, void 0, false, { 578 fileName: "<stdin>", 579 lineNumber: 3, 580 columnNumber: 15 581 }, this)); // The reference to "this" crashes here 582 } 583 } 584 ``` 585 586 The TypeScript compiler doesn't handle this at all while the Babel compiler just omits `this` for the entire constructor (even after the call to `super()`). There seems to be no specification so I can't be sure that this change doesn't break anything important. But given that Babel is pretty loose with this and TypeScript doesn't handle this at all, I'm guessing this value isn't too important. React's blog post seems to indicate that this value was intended to be used for a React-specific migration warning at some point, so it could even be that this value is irrelevant now. Anyway the crash in this case should now be fixed. 587 588 * Allow package subpath imports to map to node built-ins ([#3485](https://github.com/evanw/esbuild/issues/3485)) 589 590 You are now able to use a [subpath import](https://nodejs.org/api/packages.html#subpath-imports) in your package to resolve to a node built-in module. For example, with a `package.json` file like this: 591 592 ```json 593 { 594 "type": "module", 595 "imports": { 596 "#stream": { 597 "node": "stream", 598 "default": "./stub.js" 599 } 600 } 601 } 602 ``` 603 604 You can now import from node's `stream` module like this: 605 606 ```js 607 import * as stream from '#stream'; 608 console.log(Object.keys(stream)); 609 ``` 610 611 This will import from node's `stream` module when the platform is `node` and from `./stub.js` otherwise. 612 613 * No longer throw an error when a `Symbol` is missing ([#3453](https://github.com/evanw/esbuild/issues/3453)) 614 615 Certain JavaScript syntax features use special properties on the global `Symbol` object. For example, the asynchronous iteration syntax uses `Symbol.asyncIterator`. Previously esbuild's generated code for older browsers required this symbol to be polyfilled. However, starting with this release esbuild will use [`Symbol.for()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for) to construct these symbols if they are missing instead of throwing an error about a missing polyfill. This means your code no longer needs to include a polyfill for missing symbols as long as your code also uses `Symbol.for()` for missing symbols. 616 617 * Parse upcoming changes to TypeScript syntax ([#3490](https://github.com/evanw/esbuild/issues/3490), [#3491](https://github.com/evanw/esbuild/pull/3491)) 618 619 With this release, you can now use `from` as the name of a default type-only import in TypeScript code, as well as `of` as the name of an `await using` loop iteration variable: 620 621 ```ts 622 import type from from 'from' 623 for (await using of of of) ; 624 ``` 625 626 This matches similar changes in the TypeScript compiler ([#56376](https://github.com/microsoft/TypeScript/issues/56376) and [#55555](https://github.com/microsoft/TypeScript/issues/55555)) which will start allowing this syntax in an upcoming version of TypeScript. Please never actually write code like this. 627 628 The type-only import syntax change was contributed by [@magic-akari](https://github.com/magic-akari). 629 630 ## 0.19.5 631 632 * Fix a regression in 0.19.0 regarding `paths` in `tsconfig.json` ([#3354](https://github.com/evanw/esbuild/issues/3354)) 633 634 The fix in esbuild version 0.19.0 to process `tsconfig.json` aliases before the `--packages=external` setting unintentionally broke an edge case in esbuild's handling of certain `tsconfig.json` aliases where there are multiple files with the same name in different directories. This release adjusts esbuild's behavior for this edge case so that it passes while still processing aliases before `--packages=external`. Please read the linked issue for more details. 635 636 * Fix a CSS `font` property minification bug ([#3452](https://github.com/evanw/esbuild/issues/3452)) 637 638 This release fixes a bug where esbuild's CSS minifier didn't insert a space between the font size and the font family in the `font` CSS shorthand property in the edge case where the original source code didn't already have a space and the leading string token was shortened to an identifier: 639 640 ```css 641 /* Original code */ 642 .foo { font: 16px"Menlo"; } 643 644 /* Old output (with --minify) */ 645 .foo{font:16pxMenlo} 646 647 /* New output (with --minify) */ 648 .foo{font:16px Menlo} 649 ``` 650 651 * Fix bundling CSS with asset names containing spaces ([#3410](https://github.com/evanw/esbuild/issues/3410)) 652 653 Assets referenced via CSS `url()` tokens may cause esbuild to generate invalid output when bundling if the file name contains spaces (e.g. `url(image 2.png)`). With this release, esbuild will now quote all bundled asset references in `url()` tokens to avoid this problem. This only affects assets loaded using the `file` and `copy` loaders. 654 655 * Fix invalid CSS `url()` tokens in `@import` rules ([#3426](https://github.com/evanw/esbuild/issues/3426)) 656 657 In the future, CSS `url()` tokens may contain additional stuff after the URL. This is irrelevant today as no CSS specification does this. But esbuild previously had a bug where using these tokens in an `@import` rule resulted in malformed output. This bug has been fixed. 658 659 * Fix `browser` + `false` + `type: module` in `package.json` ([#3367](https://github.com/evanw/esbuild/issues/3367)) 660 661 The `browser` field in `package.json` allows you to map a file to `false` to have it be treated as an empty file when bundling for the browser. However, if `package.json` contains `"type": "module"` then all `.js` files will be considered ESM, not CommonJS. Importing a named import from an empty CommonJS file gives you undefined, but importing a named export from an empty ESM file is a build error. This release changes esbuild's interpretation of these files mapped to `false` in this situation from ESM to CommonJS to avoid generating build errors for named imports. 662 663 * Fix a bug in top-level await error reporting ([#3400](https://github.com/evanw/esbuild/issues/3400)) 664 665 Using `require()` on a file that contains [top-level await](https://v8.dev/features/top-level-await) is not allowed because `require()` must return synchronously and top-level await makes that impossible. You will get a build error if you try to bundle code that does this with esbuild. This release fixes a bug in esbuild's error reporting code for complex cases of this situation involving multiple levels of imports to get to the module containing the top-level await. 666 667 * Update to Unicode 15.1.0 668 669 The character tables that determine which characters form valid JavaScript identifiers have been updated from Unicode version 15.0.0 to the newly-released Unicode version 15.1.0. I'm not putting an example in the release notes because all of the new characters will likely just show up as little squares since fonts haven't been updated yet. But you can read https://www.unicode.org/versions/Unicode15.1.0/#Summary for more information about the changes. 670 671 This upgrade was contributed by [@JLHwung](https://github.com/JLHwung). 672 673 ## 0.19.4 674 675 * Fix printing of JavaScript decorators in tricky cases ([#3396](https://github.com/evanw/esbuild/issues/3396)) 676 677 This release fixes some bugs where esbuild's pretty-printing of JavaScript decorators could incorrectly produced code with a syntax error. The problem happened because esbuild sometimes substitutes identifiers for other expressions in the pretty-printer itself, but the decision about whether to wrap the expression or not didn't account for this. Here are some examples: 678 679 ```js 680 // Original code 681 import { constant } from './constants.js' 682 import { imported } from 'external' 683 import { undef } from './empty.js' 684 class Foo { 685 @constant() 686 @imported() 687 @undef() 688 foo 689 } 690 691 // Old output (with --bundle --format=cjs --packages=external --minify-syntax) 692 var import_external = require("external"); 693 var Foo = class { 694 @123() 695 @(0, import_external.imported)() 696 @(void 0)() 697 foo; 698 }; 699 700 // New output (with --bundle --format=cjs --packages=external --minify-syntax) 701 var import_external = require("external"); 702 var Foo = class { 703 @(123()) 704 @((0, import_external.imported)()) 705 @((void 0)()) 706 foo; 707 }; 708 ``` 709 710 * Allow pre-release versions to be passed to `target` ([#3388](https://github.com/evanw/esbuild/issues/3388)) 711 712 People want to be able to pass version numbers for unreleased versions of node (which have extra stuff after the version numbers) to esbuild's `target` setting and have esbuild do something reasonable with them. These version strings are of course not present in esbuild's internal feature compatibility table because an unreleased version has not been released yet (by definition). With this release, esbuild will now attempt to accept these version strings passed to `target` and do something reasonable with them. 713 714 ## 0.19.3 715 716 * Fix `list-style-type` with the `local-css` loader ([#3325](https://github.com/evanw/esbuild/issues/3325)) 717 718 The `local-css` loader incorrectly treated all identifiers provided to `list-style-type` as a custom local identifier. That included identifiers such as `none` which have special meaning in CSS, and which should not be treated as custom local identifiers. This release fixes this bug: 719 720 ```css 721 /* Original code */ 722 ul { list-style-type: none } 723 724 /* Old output (with --loader=local-css) */ 725 ul { 726 list-style-type: stdin_none; 727 } 728 729 /* New output (with --loader=local-css) */ 730 ul { 731 list-style-type: none; 732 } 733 ``` 734 735 Note that this bug only affected code using the `local-css` loader. It did not affect code using the `css` loader. 736 737 * Avoid inserting temporary variables before `use strict` ([#3322](https://github.com/evanw/esbuild/issues/3322)) 738 739 This release fixes a bug where esbuild could incorrectly insert automatically-generated temporary variables before `use strict` directives: 740 741 ```js 742 // Original code 743 function foo() { 744 'use strict' 745 a.b?.c() 746 } 747 748 // Old output (with --target=es6) 749 function foo() { 750 var _a; 751 "use strict"; 752 (_a = a.b) == null ? void 0 : _a.c(); 753 } 754 755 // New output (with --target=es6) 756 function foo() { 757 "use strict"; 758 var _a; 759 (_a = a.b) == null ? void 0 : _a.c(); 760 } 761 ``` 762 763 * Adjust TypeScript `enum` output to better approximate `tsc` ([#3329](https://github.com/evanw/esbuild/issues/3329)) 764 765 TypeScript enum values can be either number literals or string literals. Numbers create a bidirectional mapping between the name and the value but strings only create a unidirectional mapping from the name to the value. When the enum value is neither a number literal nor a string literal, TypeScript and esbuild both default to treating it as a number: 766 767 ```ts 768 // Original TypeScript code 769 declare const foo: any 770 enum Foo { 771 NUMBER = 1, 772 STRING = 'a', 773 OTHER = foo, 774 } 775 776 // Compiled JavaScript code (from "tsc") 777 var Foo; 778 (function (Foo) { 779 Foo[Foo["NUMBER"] = 1] = "NUMBER"; 780 Foo["STRING"] = "a"; 781 Foo[Foo["OTHER"] = foo] = "OTHER"; 782 })(Foo || (Foo = {})); 783 ``` 784 785 However, TypeScript does constant folding slightly differently than esbuild. For example, it may consider template literals to be string literals in some cases: 786 787 ```ts 788 // Original TypeScript code 789 declare const foo = 'foo' 790 enum Foo { 791 PRESENT = `${foo}`, 792 MISSING = `${bar}`, 793 } 794 795 // Compiled JavaScript code (from "tsc") 796 var Foo; 797 (function (Foo) { 798 Foo["PRESENT"] = "foo"; 799 Foo[Foo["MISSING"] = `${bar}`] = "MISSING"; 800 })(Foo || (Foo = {})); 801 ``` 802 803 The template literal initializer for `PRESENT` is treated as a string while the template literal initializer for `MISSING` is treated as a number. Previously esbuild treated both of these cases as a number but starting with this release, esbuild will now treat both of these cases as a string. This doesn't exactly match the behavior of `tsc` but in the case where the behavior diverges `tsc` reports a compile error, so this seems like acceptible behavior for esbuild. Note that handling these cases completely correctly would require esbuild to parse type declarations (see the `declare` keyword), which esbuild deliberately doesn't do. 804 805 * Ignore case in CSS in more places ([#3316](https://github.com/evanw/esbuild/issues/3316)) 806 807 This release makes esbuild's CSS support more case-agnostic, which better matches how browsers work. For example: 808 809 ```css 810 /* Original code */ 811 @KeyFrames Foo { From { OpaCity: 0 } To { OpaCity: 1 } } 812 body { CoLoR: YeLLoW } 813 814 /* Old output (with --minify) */ 815 @KeyFrames Foo{From {OpaCity: 0} To {OpaCity: 1}}body{CoLoR:YeLLoW} 816 817 /* New output (with --minify) */ 818 @KeyFrames Foo{0%{OpaCity:0}To{OpaCity:1}}body{CoLoR:#ff0} 819 ``` 820 821 Please never actually write code like this. 822 823 * Improve the error message for `null` entries in `exports` ([#3377](https://github.com/evanw/esbuild/issues/3377)) 824 825 Package authors can disable package export paths with the `exports` map in `package.json`. With this release, esbuild now has a clearer error message that points to the `null` token in `package.json` itself instead of to the surrounding context. Here is an example of the new error message: 826 827 ``` 828 ā [ERROR] Could not resolve "msw/browser" 829 830 lib/msw-config.ts:2:28: 831 2 ā import { setupWorker } from 'msw/browser'; 832 āµ ~~~~~~~~~~~~~ 833 834 The path "./browser" cannot be imported from package "msw" because it was explicitly disabled by 835 the package author here: 836 837 node_modules/msw/package.json:17:14: 838 17 ā "node": null, 839 āµ ~~~~ 840 841 You can mark the path "msw/browser" as external to exclude it from the bundle, which will remove 842 this error and leave the unresolved path in the bundle. 843 ``` 844 845 * Parse and print the `with` keyword in `import` statements 846 847 JavaScript was going to have a feature called "import assertions" that adds an `assert` keyword to `import` statements. It looked like this: 848 849 ```js 850 import stuff from './stuff.json' assert { type: 'json' } 851 ``` 852 853 The feature provided a way to assert that the imported file is of a certain type (but was not allowed to affect how the import is interpreted, even though that's how everyone expected it to behave). The feature was fully specified and then actually implemented and shipped in Chrome before the people behind the feature realized that they should allow it to affect how the import is interpreted after all. So import assertions are no longer going to be added to the language. 854 855 Instead, the [current proposal](https://github.com/tc39/proposal-import-attributes) is to add a feature called "import attributes" instead that adds a `with` keyword to import statements. It looks like this: 856 857 ```js 858 import stuff from './stuff.json' with { type: 'json' } 859 ``` 860 861 This feature provides a way to affect how the import is interpreted. With this release, esbuild now has preliminary support for parsing and printing this new `with` keyword. The `with` keyword is not yet interpreted by esbuild, however, so bundling code with it will generate a build error. All this release does is allow you to use esbuild to process code containing it (such as removing types from TypeScript code). Note that this syntax is not yet a part of JavaScript and may be removed or altered in the future if the specification changes (which it already has once, as described above). If that happens, esbuild reserves the right to remove or alter its support for this syntax too. 862 863 ## 0.19.2 864 865 * Update how CSS nesting is parsed again 866 867 CSS nesting syntax has been changed again, and esbuild has been updated to match. Type selectors may now be used with CSS nesting: 868 869 ```css 870 .foo { 871 div { 872 color: red; 873 } 874 } 875 ``` 876 877 Previously this was disallowed in the CSS specification because it's ambiguous whether an identifier is a declaration or a nested rule starting with a type selector without requiring unbounded lookahead in the parser. It has now been allowed because the CSS working group has decided that requiring unbounded lookahead is acceptable after all. 878 879 Note that this change means esbuild no longer considers any existing browser to support CSS nesting since none of the existing browsers support this new syntax. CSS nesting will now always be transformed when targeting a browser. This situation will change in the future as browsers add support for this new syntax. 880 881 * Fix a scope-related bug with `--drop-labels=` ([#3311](https://github.com/evanw/esbuild/issues/3311)) 882 883 The recently-released `--drop-labels=` feature previously had a bug where esbuild's internal scope stack wasn't being restored properly when a statement with a label was dropped. This could manifest as a tree-shaking issue, although it's possible that this could have also been causing other subtle problems too. The bug has been fixed in this release. 884 885 * Make renamed CSS names unique across entry points ([#3295](https://github.com/evanw/esbuild/issues/3295)) 886 887 Previously esbuild's generated names for local names in CSS were only unique within a given entry point (or across all entry points when code splitting was enabled). That meant that building multiple entry points with esbuild could result in local names being renamed to the same identifier even when those entry points were built simultaneously within a single esbuild API call. This problem was especially likely to happen with minification enabled. With this release, esbuild will now avoid renaming local names from two separate entry points to the same name if those entry points were built with a single esbuild API call, even when code splitting is disabled. 888 889 * Fix CSS ordering bug with `@layer` before `@import` 890 891 CSS lets you put `@layer` rules before `@import` rules to define the order of layers in a stylesheet. Previously esbuild's CSS bundler incorrectly ordered these after the imported files because before the introduction of cascade layers to CSS, imported files could be bundled by removing the `@import` rules and then joining files together in the right order. But with `@layer`, CSS files may now need to be split apart into multiple pieces in the bundle. For example: 892 893 ``` 894 /* Original code */ 895 @layer start; 896 @import "data:text/css,@layer inner.start;"; 897 @import "data:text/css,@layer inner.end;"; 898 @layer end; 899 900 /* Old output (with --bundle) */ 901 @layer inner.start; 902 @layer inner.end; 903 @layer start; 904 @layer end; 905 906 /* New output (with --bundle) */ 907 @layer start; 908 @layer inner.start; 909 @layer inner.end; 910 @layer end; 911 ``` 912 913 * Unwrap nested duplicate `@media` rules ([#3226](https://github.com/evanw/esbuild/issues/3226)) 914 915 With this release, esbuild's CSS minifier will now automatically unwrap duplicate nested `@media` rules: 916 917 ```css 918 /* Original code */ 919 @media (min-width: 1024px) { 920 .foo { color: red } 921 @media (min-width: 1024px) { 922 .bar { color: blue } 923 } 924 } 925 926 /* Old output (with --minify) */ 927 @media (min-width: 1024px){.foo{color:red}@media (min-width: 1024px){.bar{color:#00f}}} 928 929 /* New output (with --minify) */ 930 @media (min-width: 1024px){.foo{color:red}.bar{color:#00f}} 931 ``` 932 933 These rules are unlikely to be authored manually but may result from using frameworks such as Tailwind to generate CSS. 934 935 ## 0.19.1 936 937 * Fix a regression with `baseURL` in `tsconfig.json` ([#3307](https://github.com/evanw/esbuild/issues/3307)) 938 939 The previous release moved `tsconfig.json` path resolution before `--packages=external` checks to allow the [`paths` field](https://www.typescriptlang.org/tsconfig#paths) in `tsconfig.json` to avoid a package being marked as external. However, that reordering accidentally broke the behavior of the `baseURL` field from `tsconfig.json`. This release moves these path resolution rules around again in an attempt to allow both of these cases to work. 940 941 * Parse TypeScript type arguments for JavaScript decorators ([#3308](https://github.com/evanw/esbuild/issues/3308)) 942 943 When parsing JavaScript decorators in TypeScript (i.e. with `experimentalDecorators` disabled), esbuild previously didn't parse type arguments. Type arguments will now be parsed starting with this release. For example: 944 945 ```ts 946 @foo<number> 947 @bar<number, string>() 948 class Foo {} 949 ``` 950 951 * Fix glob patterns matching extra stuff at the end ([#3306](https://github.com/evanw/esbuild/issues/3306)) 952 953 Previously glob patterns such as `./*.js` would incorrectly behave like `./*.js*` during path matching (also matching `.js.map` files, for example). This was never intentional behavior, and has now been fixed. 954 955 * Change the permissions of esbuild's generated output files ([#3285](https://github.com/evanw/esbuild/issues/3285)) 956 957 This release changes the permissions of the output files that esbuild generates to align with the default behavior of node's [`fs.writeFileSync`](https://nodejs.org/api/fs.html#fswritefilesyncfile-data-options) function. Since most tools written in JavaScript use `fs.writeFileSync`, this should make esbuild more consistent with how other JavaScript build tools behave. 958 959 The full Unix-y details: Unix permissions use three-digit octal notation where the three digits mean "user, group, other" in that order. Within a digit, 4 means "read" and 2 means "write" and 1 means "execute". So 6 == 4 + 2 == read + write. Previously esbuild uses 0644 permissions (the leading 0 means octal notation) but the permissions for `fs.writeFileSync` defaults to 0666, so esbuild will now use 0666 permissions. This does not necessarily mean that the files esbuild generates will end up having 0666 permissions, however, as there is another Unix feature called "umask" where the operating system masks out some of these bits. If your umask is set to 0022 then the generated files will have 0644 permissions, and if your umask is set to 0002 then the generated files will have 0664 permissions. 960 961 * Fix a subtle CSS ordering issue with `@import` and `@layer` 962 963 With this release, esbuild may now introduce additional `@layer` rules when bundling CSS to better preserve the layer ordering of the input code. Here's an example of an edge case where this matters: 964 965 ```css 966 /* entry.css */ 967 @import "a.css"; 968 @import "b.css"; 969 @import "a.css"; 970 ``` 971 972 ```css 973 /* a.css */ 974 @layer a { 975 body { 976 background: red; 977 } 978 } 979 ``` 980 981 ```css 982 /* b.css */ 983 @layer b { 984 body { 985 background: green; 986 } 987 } 988 ``` 989 990 This CSS should set the body background to `green`, which is what happens in the browser. Previously esbuild generated the following output which incorrectly sets the body background to `red`: 991 992 ```css 993 /* b.css */ 994 @layer b { 995 body { 996 background: green; 997 } 998 } 999 1000 /* a.css */ 1001 @layer a { 1002 body { 1003 background: red; 1004 } 1005 } 1006 ``` 1007 1008 This difference in behavior is because the browser evaluates `a.css` + `b.css` + `a.css` (in CSS, each `@import` is replaced with a copy of the imported file) while esbuild was only writing out `b.css` + `a.css`. The first copy of `a.css` wasn't being written out by esbuild for two reasons: 1) bundlers care about code size and try to avoid emitting duplicate CSS and 2) when there are multiple copies of a CSS file, normally only the _last_ copy matters since the last declaration with equal specificity wins in CSS. 1009 1010 However, `@layer` was recently added to CSS and for `@layer` the _first_ copy matters because layers are ordered using their first location in source code order. This introduction of `@layer` means esbuild needs to change its bundling algorithm. An easy solution would be for esbuild to write out `a.css` twice, but that would be inefficient. So what I'm going to try to have esbuild do with this release is to write out an abbreviated form of the first copy of a CSS file that only includes the `@layer` information, and then still only write out the full CSS file once for the last copy. So esbuild's output for this edge case now looks like this: 1011 1012 ```css 1013 /* a.css */ 1014 @layer a; 1015 1016 /* b.css */ 1017 @layer b { 1018 body { 1019 background: green; 1020 } 1021 } 1022 1023 /* a.css */ 1024 @layer a { 1025 body { 1026 background: red; 1027 } 1028 } 1029 ``` 1030 1031 The behavior of the bundled CSS now matches the behavior of the unbundled CSS. You may be wondering why esbuild doesn't just write out `a.css` first followed by `b.css`. That would work in this case but it doesn't work in general because for any rules outside of a `@layer` rule, the last copy should still win instead of the first copy. 1032 1033 * Fix a bug with esbuild's TypeScript type definitions ([#3299](https://github.com/evanw/esbuild/pull/3299)) 1034 1035 This release fixes a copy/paste error with the TypeScript type definitions for esbuild's JS API: 1036 1037 ```diff 1038 export interface TsconfigRaw { 1039 compilerOptions?: { 1040 - baseUrl?: boolean 1041 + baseUrl?: string 1042 ... 1043 } 1044 } 1045 ``` 1046 1047 This fix was contributed by [@privatenumber](https://github.com/privatenumber). 1048 1049 ## 0.19.0 1050 1051 **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.18.0` or `~0.18.0`. See npm's documentation about [semver](https://docs.npmjs.com/cli/v6/using-npm/semver/) for more information. 1052 1053 * Handle import paths containing wildcards ([#56](https://github.com/evanw/esbuild/issues/56), [#700](https://github.com/evanw/esbuild/issues/700), [#875](https://github.com/evanw/esbuild/issues/875), [#976](https://github.com/evanw/esbuild/issues/976), [#2221](https://github.com/evanw/esbuild/issues/2221), [#2515](https://github.com/evanw/esbuild/issues/2515)) 1054 1055 This release introduces wildcards in import paths in two places: 1056 1057 * **Entry points** 1058 1059 You can now pass a string containing glob-style wildcards such as `./src/*.ts` as an entry point and esbuild will search the file system for files that match the pattern. This can be used to easily pass esbuild all files with a certain extension on the command line in a cross-platform way. Previously you had to rely on the shell to perform glob expansion, but that is obviously shell-dependent and didn't work at all on Windows. Note that to use this feature on the command line you will have to quote the pattern so it's passed verbatim to esbuild without any expansion by the shell. Here's an example: 1060 1061 ```sh 1062 esbuild --minify "./src/*.ts" --outdir=out 1063 ``` 1064 1065 Specifically the `*` character will match any character except for the `/` character, and the `/**/` character sequence will match a path separator followed by zero or more path elements. Other wildcard operators found in glob patterns such as `?` and `[...]` are not supported. 1066 1067 * **Run-time import paths** 1068 1069 Import paths that are evaluated at run-time can now be bundled in certain limited situations. The import path expression must be a form of string concatenation and must start with either `./` or `../`. Each non-string expression in the string concatenation chain becomes a wildcard. The `*` wildcard is chosen unless the previous character is a `/`, in which case the `/**/*` character sequence is used. Some examples: 1070 1071 ```js 1072 // These two forms are equivalent 1073 const json1 = await import('./data/' + kind + '.json') 1074 const json2 = await import(`./data/${kind}.json`) 1075 ``` 1076 1077 This feature works with `require(...)` and `import(...)` because these can all accept run-time expressions. It does not work with `import` and `export` statements because these cannot accept run-time expressions. If you want to prevent esbuild from trying to bundle these imports, you should move the string concatenation expression outside of the `require(...)` or `import(...)`. For example: 1078 1079 ```js 1080 // This will be bundled 1081 const json1 = await import('./data/' + kind + '.json') 1082 1083 // This will not be bundled 1084 const path = './data/' + kind + '.json' 1085 const json2 = await import(path) 1086 ``` 1087 1088 Note that using this feature means esbuild will potentially do a lot of file system I/O to find all possible files that might match the pattern. This is by design, and is not a bug. If this is a concern, I recommend either avoiding the `/**/` pattern (e.g. by not putting a `/` before a wildcard) or using this feature only in directory subtrees which do not have many files that don't match the pattern (e.g. making a subdirectory for your JSON files and explicitly including that subdirectory in the pattern). 1089 1090 * Path aliases in `tsconfig.json` no longer count as packages ([#2792](https://github.com/evanw/esbuild/issues/2792), [#3003](https://github.com/evanw/esbuild/issues/3003), [#3160](https://github.com/evanw/esbuild/issues/3160), [#3238](https://github.com/evanw/esbuild/issues/3238)) 1091 1092 Setting `--packages=external` tells esbuild to make all import paths external when they look like a package path. For example, an import of `./foo/bar` is not a package path and won't be external while an import of `foo/bar` is a package path and will be external. However, the [`paths` field](https://www.typescriptlang.org/tsconfig#paths) in `tsconfig.json` allows you to create import paths that look like package paths but that do not resolve to packages. People do not want these paths to count as package paths. So with this release, the behavior of `--packages=external` has been changed to happen after the `tsconfig.json` path remapping step. 1093 1094 * Use the `local-css` loader for `.module.css` files by default ([#20](https://github.com/evanw/esbuild/issues/20)) 1095 1096 With this release the `css` loader is still used for `.css` files except that `.module.css` files now use the `local-css` loader. This is a common convention in the web development community. If you need `.module.css` files to use the `css` loader instead, then you can override this behavior with `--loader:.module.css=css`. 1097 1098 ## 0.18.20 1099 1100 * Support advanced CSS `@import` rules ([#953](https://github.com/evanw/esbuild/issues/953), [#3137](https://github.com/evanw/esbuild/issues/3137)) 1101 1102 CSS `@import` statements have been extended to allow additional trailing tokens after the import path. These tokens sort of make the imported file behave as if it were wrapped in a `@layer`, `@supports`, and/or `@media` rule. Here are some examples: 1103 1104 ```css 1105 @import url(foo.css); 1106 @import url(foo.css) layer; 1107 @import url(foo.css) layer(bar); 1108 @import url(foo.css) layer(bar) supports(display: flex); 1109 @import url(foo.css) layer(bar) supports(display: flex) print; 1110 @import url(foo.css) layer(bar) print; 1111 @import url(foo.css) supports(display: flex); 1112 @import url(foo.css) supports(display: flex) print; 1113 @import url(foo.css) print; 1114 ``` 1115 1116 You can read more about this advanced syntax [here](https://developer.mozilla.org/en-US/docs/Web/CSS/@import). With this release, esbuild will now bundle `@import` rules with these trailing tokens and will wrap the imported files in the corresponding rules. Note that this now means a given imported file can potentially appear in multiple places in the bundle. However, esbuild will still only load it once (e.g. on-load plugins will only run once per file, not once per import). 1117 1118 ## 0.18.19 1119 1120 * Implement `composes` from CSS modules ([#20](https://github.com/evanw/esbuild/issues/20)) 1121 1122 This release implements the `composes` annotation from the [CSS modules specification](https://github.com/css-modules/css-modules#composition). It provides a way for class selectors to reference other class selectors (assuming you are using the `local-css` loader). And with the `from` syntax, this can even work with local names across CSS files. For example: 1123 1124 ```js 1125 // app.js 1126 import { submit } from './style.css' 1127 const div = document.createElement('div') 1128 div.className = submit 1129 document.body.appendChild(div) 1130 ``` 1131 1132 ```css 1133 /* style.css */ 1134 .button { 1135 composes: pulse from "anim.css"; 1136 display: inline-block; 1137 } 1138 .submit { 1139 composes: button; 1140 font-weight: bold; 1141 } 1142 ``` 1143 1144 ```css 1145 /* anim.css */ 1146 @keyframes pulse { 1147 from, to { opacity: 1 } 1148 50% { opacity: 0.5 } 1149 } 1150 .pulse { 1151 animation: 2s ease-in-out infinite pulse; 1152 } 1153 ``` 1154 1155 Bundling this with esbuild using `--bundle --outdir=dist --loader:.css=local-css` now gives the following: 1156 1157 ```js 1158 (() => { 1159 // style.css 1160 var submit = "anim_pulse style_button style_submit"; 1161 1162 // app.js 1163 var div = document.createElement("div"); 1164 div.className = submit; 1165 document.body.appendChild(div); 1166 })(); 1167 ``` 1168 1169 ```css 1170 /* anim.css */ 1171 @keyframes anim_pulse { 1172 from, to { 1173 opacity: 1; 1174 } 1175 50% { 1176 opacity: 0.5; 1177 } 1178 } 1179 .anim_pulse { 1180 animation: 2s ease-in-out infinite anim_pulse; 1181 } 1182 1183 /* style.css */ 1184 .style_button { 1185 display: inline-block; 1186 } 1187 .style_submit { 1188 font-weight: bold; 1189 } 1190 ``` 1191 1192 Import paths in the `composes: ... from` syntax are resolved using the new `composes-from` import kind, which can be intercepted by plugins during import path resolution when bundling is enabled. 1193 1194 Note that the order in which composed CSS classes from separate files appear in the bundled output file is deliberately _**undefined**_ by design (see [the specification](https://github.com/css-modules/css-modules#composing-from-other-files) for details). You are not supposed to declare the same CSS property in two separate class selectors and then compose them together. You are only supposed to compose CSS class selectors that declare non-overlapping CSS properties. 1195 1196 Issue [#20](https://github.com/evanw/esbuild/issues/20) (the issue tracking CSS modules) is esbuild's most-upvoted issue! With this change, I now consider esbuild's implementation of CSS modules to be complete. There are still improvements to make and there may also be bugs with the current implementation, but these can be tracked in separate issues. 1197 1198 * Fix non-determinism with `tsconfig.json` and symlinks ([#3284](https://github.com/evanw/esbuild/issues/3284)) 1199 1200 This release fixes an issue that could cause esbuild to sometimes emit incorrect build output in cases where a file under the effect of `tsconfig.json` is inconsistently referenced through a symlink. It can happen when using `npm link` to create a symlink within `node_modules` to an unpublished package. The build result was non-deterministic because esbuild runs module resolution in parallel and the result of the `tsconfig.json` lookup depended on whether the import through the symlink or not through the symlink was resolved first. This problem was fixed by moving the `realpath` operation before the `tsconfig.json` lookup. 1201 1202 * Add a `hash` property to output files ([#3084](https://github.com/evanw/esbuild/issues/3084), [#3293](https://github.com/evanw/esbuild/issues/3293)) 1203 1204 As a convenience, every output file in esbuild's API now includes a `hash` property that is a hash of the `contents` field. This is the hash that's used internally by esbuild to detect changes between builds for esbuild's live-reload feature. You may also use it to detect changes between your own builds if its properties are sufficient for your use case. 1205 1206 This feature has been added directly to output file objects since it's just a hash of the `contents` field, so it makes conceptual sense to store it in the same location. Another benefit of putting it there instead of including it as a part of the watch mode API is that it can be used without watch mode enabled. You can use it to compare the output of two independent builds that were done at different times. 1207 1208 The hash algorithm (currently [XXH64](https://xxhash.com/)) is implementation-dependent and may be changed at any time in between esbuild versions. If you don't like esbuild's choice of hash algorithm then you are welcome to hash the contents yourself instead. As with any hash algorithm, note that while two different hashes mean that the contents are different, two equal hashes do not necessarily mean that the contents are equal. You may still want to compare the contents in addition to the hashes to detect with certainty when output files have been changed. 1209 1210 * Avoid generating duplicate prefixed declarations in CSS ([#3292](https://github.com/evanw/esbuild/issues/3292)) 1211 1212 There was a request for esbuild's CSS prefixer to avoid generating a prefixed declaration if a declaration by that name is already present in the same rule block. So with this release, esbuild will now avoid doing this: 1213 1214 ```css 1215 /* Original code */ 1216 body { 1217 backdrop-filter: blur(30px); 1218 -webkit-backdrop-filter: blur(45px); 1219 } 1220 1221 /* Old output (with --target=safari12) */ 1222 body { 1223 -webkit-backdrop-filter: blur(30px); 1224 backdrop-filter: blur(30px); 1225 -webkit-backdrop-filter: blur(45px); 1226 } 1227 1228 /* New output (with --target=safari12) */ 1229 body { 1230 backdrop-filter: blur(30px); 1231 -webkit-backdrop-filter: blur(45px); 1232 } 1233 ``` 1234 1235 This can result in a visual difference in certain cases (for example if the browser understands `blur(30px)` but not `blur(45px)`, it will be able to fall back to `blur(30px)`). But this change means esbuild now matches the behavior of [Autoprefixer](https://autoprefixer.github.io/) which is probably a good representation of how people expect this feature to work. 1236 1237 ## 0.18.18 1238 1239 * Fix asset references with the `--line-limit` flag ([#3286](https://github.com/evanw/esbuild/issues/3286)) 1240 1241 The recently-released `--line-limit` flag tells esbuild to terminate long lines after they pass this length limit. This includes automatically wrapping long strings across multiple lines using escaped newline syntax. However, using this could cause esbuild to generate incorrect code for references from generated output files to assets in the bundle (i.e. files loaded with the `file` or `copy` loaders). This is because esbuild implements asset references internally using find-and-replace with a randomly-generated string, but the find operation fails if the string is split by an escaped newline due to line wrapping. This release fixes the problem by not wrapping these strings. This issue affected asset references in both JS and CSS files. 1242 1243 * Support local names in CSS for `@keyframe`, `@counter-style`, and `@container` ([#20](https://github.com/evanw/esbuild/issues/20)) 1244 1245 This release extends support for local names in CSS files loaded with the `local-css` loader to cover the `@keyframe`, `@counter-style`, and `@container` rules (and also `animation`, `list-style`, and `container` declarations). Here's an example: 1246 1247 ```css 1248 @keyframes pulse { 1249 from, to { opacity: 1 } 1250 50% { opacity: 0.5 } 1251 } 1252 @counter-style moon { 1253 system: cyclic; 1254 symbols: š š š š š š š š; 1255 } 1256 @container squish { 1257 li { float: left } 1258 } 1259 ul { 1260 animation: 2s ease-in-out infinite pulse; 1261 list-style: inside moon; 1262 container: squish / size; 1263 } 1264 ``` 1265 1266 With the `local-css` loader enabled, that CSS will be turned into something like this (with the local name mapping exposed to JS): 1267 1268 ```css 1269 @keyframes stdin_pulse { 1270 from, to { 1271 opacity: 1; 1272 } 1273 50% { 1274 opacity: 0.5; 1275 } 1276 } 1277 @counter-style stdin_moon { 1278 system: cyclic; 1279 symbols: š š š š š š š š; 1280 } 1281 @container stdin_squish { 1282 li { 1283 float: left; 1284 } 1285 } 1286 ul { 1287 animation: 2s ease-in-out infinite stdin_pulse; 1288 list-style: inside stdin_moon; 1289 container: stdin_squish / size; 1290 } 1291 ``` 1292 1293 If you want to use a global name within a file loaded with the `local-css` loader, you can use a `:global` selector to do that: 1294 1295 ```css 1296 div { 1297 /* All symbols are global inside this scope (i.e. 1298 * "pulse", "moon", and "squish" are global below) */ 1299 :global { 1300 animation: 2s ease-in-out infinite pulse; 1301 list-style: inside moon; 1302 container: squish / size; 1303 } 1304 } 1305 ``` 1306 1307 If you want to use `@keyframes`, `@counter-style`, or `@container` with a global name, make sure it's in a file that uses the `css` or `global-css` loader instead of the `local-css` loader. For example, you can configure `--loader:.module.css=local-css` so that the `local-css` loader only applies to `*.module.css` files. 1308 1309 * Support strings as keyframe animation names in CSS ([#2555](https://github.com/evanw/esbuild/issues/2555)) 1310 1311 With this release, esbuild will now parse animation names that are specified as strings and will convert them to identifiers. The CSS specification allows animation names to be specified using either identifiers or strings but Chrome only understands identifiers, so esbuild will now always convert string names to identifier names for Chrome compatibility: 1312 1313 ```css 1314 /* Original code */ 1315 @keyframes "hide menu" { 1316 from { opacity: 1 } 1317 to { opacity: 0 } 1318 } 1319 menu.hide { 1320 animation: 0.5s ease-in-out "hide menu"; 1321 } 1322 1323 /* Old output */ 1324 @keyframes "hide menu" { from { opacity: 1 } to { opacity: 0 } } 1325 menu.hide { 1326 animation: 0.5s ease-in-out "hide menu"; 1327 } 1328 1329 /* New output */ 1330 @keyframes hide\ menu { 1331 from { 1332 opacity: 1; 1333 } 1334 to { 1335 opacity: 0; 1336 } 1337 } 1338 menu.hide { 1339 animation: 0.5s ease-in-out hide\ menu; 1340 } 1341 ``` 1342 1343 ## 0.18.17 1344 1345 * Support `An+B` syntax and `:nth-*()` pseudo-classes in CSS 1346 1347 This adds support for the `:nth-child()`, `:nth-last-child()`, `:nth-of-type()`, and `:nth-last-of-type()` pseudo-classes to esbuild, which has the following consequences: 1348 1349 * The [`An+B` syntax](https://drafts.csswg.org/css-syntax-3/#anb-microsyntax) is now parsed, so parse errors are now reported 1350 * `An+B` values inside these pseudo-classes are now pretty-printed (e.g. a leading `+` will be stripped because it's not in the AST) 1351 * When minification is enabled, `An+B` values are reduced to equivalent but shorter forms (e.g. `2n+0` => `2n`, `2n+1` => `odd`) 1352 * Local CSS names in an `of` clause are now detected (e.g. in `:nth-child(2n of :local(.foo))` the name `foo` is now renamed) 1353 1354 ```css 1355 /* Original code */ 1356 .foo:nth-child(+2n+1 of :local(.bar)) { 1357 color: red; 1358 } 1359 1360 /* Old output (with --loader=local-css) */ 1361 .stdin_foo:nth-child(+2n + 1 of :local(.bar)) { 1362 color: red; 1363 } 1364 1365 /* New output (with --loader=local-css) */ 1366 .stdin_foo:nth-child(2n+1 of .stdin_bar) { 1367 color: red; 1368 } 1369 ``` 1370 1371 * Adjust CSS nesting parser for IE7 hacks ([#3272](https://github.com/evanw/esbuild/issues/3272)) 1372 1373 This fixes a regression with esbuild's treatment of IE7 hacks in CSS. CSS nesting allows selectors to be used where declarations are expected. There's an IE7 hack where prefixing a declaration with a `*` causes that declaration to only be applied in IE7 due to a bug in IE7's CSS parser. However, it's valid for nested CSS selectors to start with `*`. So esbuild was incorrectly parsing these declarations and anything following it up until the next `{` as a selector for a nested CSS rule. This release changes esbuild's parser to terminate the parsing of selectors for nested CSS rules when a `;` is encountered to fix this edge case: 1374 1375 ```css 1376 /* Original code */ 1377 .item { 1378 *width: 100%; 1379 height: 1px; 1380 } 1381 1382 /* Old output */ 1383 .item { 1384 *width: 100%; height: 1px; { 1385 } 1386 } 1387 1388 /* New output */ 1389 .item { 1390 *width: 100%; 1391 height: 1px; 1392 } 1393 ``` 1394 1395 Note that the syntax for CSS nesting is [about to change again](https://github.com/w3c/csswg-drafts/issues/7961), so esbuild's CSS parser may still not be completely accurate with how browsers do and/or will interpret CSS nesting syntax. Expect additional updates to esbuild's CSS parser in the future to deal with upcoming CSS specification changes. 1396 1397 * Adjust esbuild's warning about undefined imports for TypeScript `import` equals declarations ([#3271](https://github.com/evanw/esbuild/issues/3271)) 1398 1399 In JavaScript, accessing a missing property on an import namespace object is supposed to result in a value of `undefined` at run-time instead of an error at compile-time. This is something that esbuild warns you about by default because doing this can indicate a bug with your code. For example: 1400 1401 ```js 1402 // app.js 1403 import * as styles from './styles' 1404 console.log(styles.buton) 1405 ``` 1406 1407 ```js 1408 // styles.js 1409 export let button = {} 1410 ``` 1411 1412 If you bundle `app.js` with esbuild you will get this: 1413 1414 ``` 1415 ā² [WARNING] Import "buton" will always be undefined because there is no matching export in "styles.js" [import-is-undefined] 1416 1417 app.js:2:19: 1418 2 ā console.log(styles.buton) 1419 ā ~~~~~ 1420 āµ button 1421 1422 Did you mean to import "button" instead? 1423 1424 styles.js:1:11: 1425 1 ā export let button = {} 1426 āµ ~~~~~~ 1427 ``` 1428 1429 However, there is TypeScript-only syntax for `import` equals declarations that can represent either a type import (which esbuild should ignore) or a value import (which esbuild should respect). Since esbuild doesn't have a type system, it tries to only respect `import` equals declarations that are actually used as values. Previously esbuild always generated this warning for unused imports referenced within `import` equals declarations even when the reference could be a type instead of a value. Starting with this release, esbuild will now only warn in this case if the import is actually used. Here is an example of some code that no longer causes an incorrect warning: 1430 1431 ```ts 1432 // app.ts 1433 import * as styles from './styles' 1434 import ButtonType = styles.Button 1435 ``` 1436 1437 ```ts 1438 // styles.ts 1439 export interface Button {} 1440 ``` 1441 1442 ## 0.18.16 1443 1444 * Fix a regression with whitespace inside `:is()` ([#3265](https://github.com/evanw/esbuild/issues/3265)) 1445 1446 The change to parse the contents of `:is()` in version 0.18.14 introduced a regression that incorrectly flagged the contents as a syntax error if the contents started with a whitespace token (for example `div:is( .foo ) {}`). This regression has been fixed. 1447 1448 ## 0.18.15 1449 1450 * Add the `--serve-fallback=` option ([#2904](https://github.com/evanw/esbuild/issues/2904)) 1451 1452 The web server built into esbuild serves the latest in-memory results of the configured build. If the requested path doesn't match any in-memory build result, esbuild also provides the `--servedir=` option to tell esbuild to serve the requested path from that directory instead. And if the requested path doesn't match either of those things, esbuild will either automatically generate a directory listing (for directories) or return a 404 error. 1453 1454 Starting with this release, that last step can now be replaced with telling esbuild to serve a specific HTML file using the `--serve-fallback=` option. This can be used to provide a "not found" page for missing URLs. It can also be used to implement a [single-page app](https://en.wikipedia.org/wiki/Single-page_application) that mutates the current URL and therefore requires the single app entry point to be served when the page is loaded regardless of whatever the current URL is. 1455 1456 * Use the `tsconfig` field in `package.json` during `extends` resolution ([#3247](https://github.com/evanw/esbuild/issues/3247)) 1457 1458 This release adds a feature from [TypeScript 3.2](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-2.html#tsconfigjson-inheritance-via-nodejs-packages) where if a `tsconfig.json` file specifies a package name in the `extends` field and that package's `package.json` file has a `tsconfig` field, the contents of that field are used in the search for the base `tsconfig.json` file. 1459 1460 * Implement CSS nesting without `:is()` when possible ([#1945](https://github.com/evanw/esbuild/issues/1945)) 1461 1462 Previously esbuild would always produce a warning when transforming nested CSS for a browser that doesn't support the `:is()` pseudo-class. This was because the nesting transform needs to generate an `:is()` in some complex cases which means the transformed CSS would then not work in that browser. However, the CSS nesting transform can often be done without generating an `:is()`. So with this release, esbuild will no longer warn when targeting browsers that don't support `:is()` in the cases where an `:is()` isn't needed to represent the nested CSS. 1463 1464 In addition, esbuild's nested CSS transform has been updated to avoid generating an `:is()` in cases where an `:is()` is preferable but there's a longer alternative that is also equivalent. This update means esbuild can now generate a combinatorial explosion of CSS for complex CSS nesting syntax when targeting browsers that don't support `:is()`. This combinatorial explosion is necessary to accurately represent the original semantics. For example: 1465 1466 ```css 1467 /* Original code */ 1468 .first, 1469 .second, 1470 .third { 1471 & > & { 1472 color: red; 1473 } 1474 } 1475 1476 /* Old output (with --target=chrome80) */ 1477 :is(.first, .second, .third) > :is(.first, .second, .third) { 1478 color: red; 1479 } 1480 1481 /* New output (with --target=chrome80) */ 1482 .first > .first, 1483 .first > .second, 1484 .first > .third, 1485 .second > .first, 1486 .second > .second, 1487 .second > .third, 1488 .third > .first, 1489 .third > .second, 1490 .third > .third { 1491 color: red; 1492 } 1493 ``` 1494 1495 This change means you can now use CSS nesting with esbuild when targeting an older browser that doesn't support `:is()`. You'll now only get a warning from esbuild if you use complex CSS nesting syntax that esbuild can't represent in that older browser without using `:is()`. There are two such cases: 1496 1497 ```css 1498 /* Case 1 */ 1499 a b { 1500 .foo & { 1501 color: red; 1502 } 1503 } 1504 1505 /* Case 2 */ 1506 a { 1507 > b& { 1508 color: red; 1509 } 1510 } 1511 ``` 1512 1513 These two cases still need to use `:is()`, both for different reasons, and cannot be used when targeting an older browser that doesn't support `:is()`: 1514 1515 ```css 1516 /* Case 1 */ 1517 .foo :is(a b) { 1518 color: red; 1519 } 1520 1521 /* Case 2 */ 1522 a > a:is(b) { 1523 color: red; 1524 } 1525 ``` 1526 1527 * Automatically lower `inset` in CSS for older browsers 1528 1529 With this release, esbuild will now automatically expand the `inset` property to the `top`, `right`, `bottom`, and `left` properties when esbuild's `target` is set to a browser that doesn't support `inset`: 1530 1531 ```css 1532 /* Original code */ 1533 .app { 1534 position: absolute; 1535 inset: 10px 20px; 1536 } 1537 1538 /* Old output (with --target=chrome80) */ 1539 .app { 1540 position: absolute; 1541 inset: 10px 20px; 1542 } 1543 1544 /* New output (with --target=chrome80) */ 1545 .app { 1546 position: absolute; 1547 top: 10px; 1548 right: 20px; 1549 bottom: 10px; 1550 left: 20px; 1551 } 1552 ``` 1553 1554 * Add support for the new [`@starting-style`](https://drafts.csswg.org/css-transitions-2/#defining-before-change-style-the-starting-style-rule) CSS rule ([#3249](https://github.com/evanw/esbuild/pull/3249)) 1555 1556 This at rule allow authors to start CSS transitions on first style update. That is, you can now make the transition take effect when the `display` property changes from `none` to `block`. 1557 1558 ```css 1559 /* Original code */ 1560 @starting-style { 1561 h1 { 1562 background-color: transparent; 1563 } 1564 } 1565 1566 /* Output */ 1567 @starting-style{h1{background-color:transparent}} 1568 ``` 1569 1570 This was contributed by [@yisibl](https://github.com/yisibl). 1571 1572 ## 0.18.14 1573 1574 * Implement local CSS names ([#20](https://github.com/evanw/esbuild/issues/20)) 1575 1576 This release introduces two new loaders called `global-css` and `local-css` and two new pseudo-class selectors `:local()` and `:global()`. This is a partial implementation of the popular [CSS modules](https://github.com/css-modules/css-modules) approach for avoiding unintentional name collisions in CSS. I'm not calling this feature "CSS modules" because although some people in the community call it that, other people in the community have started using "CSS modules" to refer to [something completely different](https://github.com/WICG/webcomponents/blob/60c9f682b63c622bfa0d8222ea6b1f3b659e007c/proposals/css-modules-v1-explainer.md) and now CSS modules is an overloaded term. 1577 1578 Here's how this new local CSS name feature works with esbuild: 1579 1580 * Identifiers that look like `.className` and `#idName` are global with the `global-css` loader and local with the `local-css` loader. Global identifiers are the same across all files (the way CSS normally works) but local identifiers are different between different files. If two separate CSS files use the same local identifier `.button`, esbuild will automatically rename one of them so that they don't collide. This is analogous to how esbuild automatically renames JS local variables with the same name in separate JS files to avoid name collisions. 1581 1582 * It only makes sense to use local CSS names with esbuild when you are also using esbuild's bundler to bundle JS files that import CSS files. When you do that, esbuild will generate one export for each local name in the CSS file. The JS code can import these names and use them when constructing HTML DOM. For example: 1583 1584 ```js 1585 // app.js 1586 import { outerShell } from './app.css' 1587 const div = document.createElement('div') 1588 div.className = outerShell 1589 document.body.appendChild(div) 1590 ``` 1591 1592 ```css 1593 /* app.css */ 1594 .outerShell { 1595 position: absolute; 1596 inset: 0; 1597 } 1598 ``` 1599 1600 When you bundle this with `esbuild app.js --bundle --loader:.css=local-css --outdir=out` you'll now get this (notice how the local CSS name `outerShell` has been renamed): 1601 1602 ```js 1603 // out/app.js 1604 (() => { 1605 // app.css 1606 var outerShell = "app_outerShell"; 1607 1608 // app.js 1609 var div = document.createElement("div"); 1610 div.className = outerShell; 1611 document.body.appendChild(div); 1612 })(); 1613 ``` 1614 1615 ```css 1616 /* out/app.css */ 1617 .app_outerShell { 1618 position: absolute; 1619 inset: 0; 1620 } 1621 ``` 1622 1623 This feature only makes sense to use when bundling is enabled both because your code needs to `import` the renamed local names so that it can use them, and because esbuild needs to be able to process all CSS files containing local names in a single bundling operation so that it can successfully rename conflicting local names to avoid collisions. 1624 1625 * If you are in a global CSS file (with the `global-css` loader) you can create a local name using `:local()`, and if you are in a local CSS file (with the `local-css` loader) you can create a global name with `:global()`. So the choice of the `global-css` loader vs. the `local-css` loader just sets the default behavior for identifiers, but you can override it on a case-by-case basis as necessary. For example: 1626 1627 ```css 1628 :local(.button) { 1629 color: red; 1630 } 1631 :global(.button) { 1632 color: blue; 1633 } 1634 ``` 1635 1636 Processing this CSS file with esbuild with either the `global-css` or `local-css` loader will result in something like this: 1637 1638 ```css 1639 .stdin_button { 1640 color: red; 1641 } 1642 .button { 1643 color: blue; 1644 } 1645 ``` 1646 1647 * The names that esbuild generates for local CSS names are an implementation detail and are not intended to be hard-coded anywhere. The only way you should be referencing the local CSS names in your JS or HTML is with an `import` statement in JS that is bundled with esbuild, as demonstrated above. For example, when `--minify` is enabled esbuild will use a different name generation algorithm which generates names that are as short as possible (analogous to how esbuild minifies local identifiers in JS). 1648 1649 * You can easily use both global CSS files and local CSS files simultaneously if you give them different file extensions. For example, you could pass `--loader:.css=global-css` and `--loader:.module.css=local-css` to esbuild so that `.css` files still use global names by default but `.module.css` files use local names by default. 1650 1651 * Keep in mind that the `css` loader is different than the `global-css` loader. The `:local` and `:global` annotations are not enabled with the `css` loader and will be passed through unchanged. This allows you to have the option of using esbuild to process CSS containing while preserving these annotations. It also means that local CSS names are disabled by default for now (since the `css` loader is currently the default for CSS files). The `:local` and `:global` syntax may be enabled by default in a future release. 1652 1653 Note that esbuild's implementation does not currently have feature parity with other implementations of modular CSS in similar tools. This is only a preliminary release with a partial implementation that includes some basic behavior to get the process started. Additional behavior may be added in future releases. In particular, this release does not implement: 1654 1655 * The `composes` pragma 1656 * Tree shaking for unused local CSS 1657 * Local names for keyframe animations, grid lines, `@container`, `@counter-style`, etc. 1658 1659 Issue [#20](https://github.com/evanw/esbuild/issues/20) (the issue for this feature) is esbuild's most-upvoted issue! While this release still leaves that issue open, it's an important first step in that direction. 1660 1661 * Parse `:is`, `:has`, `:not`, and `:where` in CSS 1662 1663 With this release, esbuild will now parse the contents of these pseudo-class selectors as a selector list. This means you will now get syntax warnings within these selectors for invalid selector syntax. It also means that esbuild's CSS nesting transform behaves slightly differently than before because esbuild is now operating on an AST instead of a token stream. For example: 1664 1665 ```css 1666 /* Original code */ 1667 div { 1668 :where(.foo&) { 1669 color: red; 1670 } 1671 } 1672 1673 /* Old output (with --target=chrome90) */ 1674 :where(.foo:is(div)) { 1675 color: red; 1676 } 1677 1678 /* New output (with --target=chrome90) */ 1679 :where(div.foo) { 1680 color: red; 1681 } 1682 ``` 1683 1684 ## 0.18.13 1685 1686 * Add the `--drop-labels=` option ([#2398](https://github.com/evanw/esbuild/issues/2398)) 1687 1688 If you want to conditionally disable some development-only code and have it not be present in the final production bundle, right now the most straightforward way of doing this is to use the `--define:` flag along with a specially-named global variable. For example, consider the following code: 1689 1690 ```js 1691 function main() { 1692 DEV && doAnExpensiveCheck() 1693 } 1694 ``` 1695 1696 You can build this for development and production like this: 1697 1698 * Development: `esbuild --define:DEV=true` 1699 * Production: `esbuild --define:DEV=false` 1700 1701 One drawback of this approach is that the resulting code crashes if you don't provide a value for `DEV` with `--define:`. In practice this isn't that big of a problem, and there are also various ways to work around this. 1702 1703 However, another approach that avoids this drawback is to use JavaScript label statements instead. That's what the `--drop-labels=` flag implements. For example, consider the following code: 1704 1705 ```js 1706 function main() { 1707 DEV: doAnExpensiveCheck() 1708 } 1709 ``` 1710 1711 With this release, you can now build this for development and production like this: 1712 1713 * Development: `esbuild` 1714 * Production: `esbuild --drop-labels=DEV` 1715 1716 This means that code containing optional development-only checks can now be written such that it's safe to run without any additional configuration. The `--drop-labels=` flag takes comma-separated list of multiple label names to drop. 1717 1718 * Avoid causing `unhandledRejection` during shutdown ([#3219](https://github.com/evanw/esbuild/issues/3219)) 1719 1720 All pending esbuild JavaScript API calls are supposed to fail if esbuild's underlying child process is unexpectedly terminated. This can happen if `SIGINT` is sent to the parent `node` process with Ctrl+C, for example. Previously doing this could also cause an unhandled promise rejection when esbuild attempted to communicate this failure to its own child process that no longer exists. This release now swallows this communication failure, which should prevent this internal unhandled promise rejection. This change means that you can now use esbuild's JavaScript API with a custom `SIGINT` handler that extends the lifetime of the `node` process without esbuild's internals causing an early exit due to an unhandled promise rejection. 1721 1722 * Update browser compatibility table scripts 1723 1724 The scripts that esbuild uses to compile its internal browser compatibility table have been overhauled. Briefly: 1725 1726 * Converted from JavaScript to TypeScript 1727 * Fixed some bugs that resulted in small changes to the table 1728 * Added [`caniuse-lite`](https://www.npmjs.com/package/caniuse-lite) and [`@mdn/browser-compat-data`](https://www.npmjs.com/package/@mdn/browser-compat-data) as new data sources (replacing manually-copied information) 1729 1730 This change means it's now much easier to keep esbuild's internal compatibility tables up to date. You can review the table changes here if you need to debug something about this change: 1731 1732 * [JS table changes](https://github.com/evanw/esbuild/compare/d259b8fac717ee347c19bd8299f2c26d7c87481a...af1d35c372f78c14f364b63e819fd69548508f55#diff-1649eb68992c79753469f02c097de309adaf7231b45cc816c50bf751af400eb4) 1733 * [CSS table changes](https://github.com/evanw/esbuild/commit/95feb2e09877597cb929469ce43811bdf11f50c1#diff-4e1c4f269e02c5ea31cbd5138d66751e32cf0e240524ee8a966ac756f0e3c3cd) 1734 1735 ## 0.18.12 1736 1737 * Fix a panic with `const enum` inside parentheses ([#3205](https://github.com/evanw/esbuild/issues/3205)) 1738 1739 This release fixes an edge case where esbuild could potentially panic if a TypeScript `const enum` statement was used inside of a parenthesized expression and was followed by certain other scope-related statements. Here's a minimal example that triggers this edge case: 1740 1741 ```ts 1742 (() => { 1743 const enum E { a }; 1744 () => E.a 1745 }) 1746 ``` 1747 1748 * Allow a newline in the middle of TypeScript `export type` statement ([#3225](https://github.com/evanw/esbuild/issues/3225)) 1749 1750 Previously esbuild incorrectly rejected the following valid TypeScript code: 1751 1752 ```ts 1753 export type 1754 { T }; 1755 1756 export type 1757 * as foo from 'bar'; 1758 ``` 1759 1760 Code that uses a newline after `export type` is now allowed starting with this release. 1761 1762 * Fix cross-module inlining of string enums ([#3210](https://github.com/evanw/esbuild/issues/3210)) 1763 1764 A refactoring typo in version 0.18.9 accidentally introduced a regression with cross-module inlining of string enums when combined with computed property accesses. This regression has been fixed. 1765 1766 * Rewrite `.js` to `.ts` inside packages with `exports` ([#3201](https://github.com/evanw/esbuild/issues/3201)) 1767 1768 Packages with the `exports` field are supposed to disable node's path resolution behavior that allows you to import a file with a different extension than the one in the source code (for example, importing `foo/bar` to get `foo/bar.js`). And TypeScript has behavior where you can import a non-existent `.js` file and you will get the `.ts` file instead. Previously the presence of the `exports` field caused esbuild to disable all extension manipulation stuff which included both node's implicit file extension searching and TypeScript's file extension swapping. However, TypeScript appears to always apply file extension swapping even in this case. So with this release, esbuild will now rewrite `.js` to `.ts` even inside packages with `exports`. 1769 1770 * Fix a redirect edge case in esbuild's development server ([#3208](https://github.com/evanw/esbuild/issues/3208)) 1771 1772 The development server canonicalizes directory URLs by adding a trailing slash. For example, visiting `/about` redirects to `/about/` if `/about/index.html` would be served. However, if the requested path begins with two slashes, then the redirect incorrectly turned into a protocol-relative URL. For example, visiting `//about` redirected to `//about/` which the browser turns into `http://about/`. This release fixes the bug by canonicalizing the URL path when doing this redirect. 1773 1774 ## 0.18.11 1775 1776 * Fix a TypeScript code generation edge case ([#3199](https://github.com/evanw/esbuild/issues/3199)) 1777 1778 This release fixes a regression in version 0.18.4 where using a TypeScript `namespace` that exports a `class` declaration combined with `--keep-names` and a `--target` of `es2021` or earlier could cause esbuild to export the class from the namespace using an incorrect name (notice the assignment to `X2._Y` vs. `X2.Y`): 1779 1780 ```ts 1781 // Original code 1782 1783 // Old output (with --keep-names --target=es2021) 1784 var X; 1785 ((X2) => { 1786 const _Y = class _Y { 1787 }; 1788 __name(_Y, "Y"); 1789 let Y = _Y; 1790 X2._Y = _Y; 1791 })(X || (X = {})); 1792 1793 // New output (with --keep-names --target=es2021) 1794 var X; 1795 ((X2) => { 1796 const _Y = class _Y { 1797 }; 1798 __name(_Y, "Y"); 1799 let Y = _Y; 1800 X2.Y = _Y; 1801 })(X || (X = {})); 1802 ``` 1803 1804 ## 0.18.10 1805 1806 * Fix a tree-shaking bug that removed side effects ([#3195](https://github.com/evanw/esbuild/issues/3195)) 1807 1808 This fixes a regression in version 0.18.4 where combining `--minify-syntax` with `--keep-names` could cause expressions with side effects after a function declaration to be considered side-effect free for tree shaking purposes. The reason was because `--keep-names` generates an expression statement containing a call to a helper function after the function declaration with a special flag that makes the function call able to be tree shaken, and then `--minify-syntax` could potentially merge that expression statement with following expressions without clearing the flag. This release fixes the bug by clearing the flag when merging expression statements together. 1809 1810 * Fix an incorrect warning about CSS nesting ([#3197](https://github.com/evanw/esbuild/issues/3197)) 1811 1812 A warning is currently generated when transforming nested CSS to a browser that doesn't support `:is()` because transformed nested CSS may need to use that feature to represent nesting. This was previously always triggered when an at-rule was encountered in a declaration context. Typically the only case you would encounter this is when using CSS nesting within a selector rule. However, there is a case where that's not true: when using a margin at-rule such as `@top-left` within `@page`. This release avoids incorrectly generating a warning in this case by checking that the at-rule is within a selector rule before generating a warning. 1813 1814 ## 0.18.9 1815 1816 * Fix `await using` declarations inside `async` generator functions 1817 1818 I forgot about the new `await using` declarations when implementing lowering for `async` generator functions in the previous release. This change fixes the transformation of `await using` declarations when they are inside lowered `async` generator functions: 1819 1820 ```js 1821 // Original code 1822 async function* foo() { 1823 await using x = await y 1824 } 1825 1826 // Old output (with --supported:async-generator=false) 1827 function foo() { 1828 return __asyncGenerator(this, null, function* () { 1829 await using x = yield new __await(y); 1830 }); 1831 } 1832 1833 // New output (with --supported:async-generator=false) 1834 function foo() { 1835 return __asyncGenerator(this, null, function* () { 1836 var _stack = []; 1837 try { 1838 const x = __using(_stack, yield new __await(y), true); 1839 } catch (_) { 1840 var _error = _, _hasError = true; 1841 } finally { 1842 var _promise = __callDispose(_stack, _error, _hasError); 1843 _promise && (yield new __await(_promise)); 1844 } 1845 }); 1846 } 1847 ``` 1848 1849 * Insert some prefixed CSS properties when appropriate ([#3122](https://github.com/evanw/esbuild/issues/3122)) 1850 1851 With this release, esbuild will now insert prefixed CSS properties in certain cases when the `target` setting includes browsers that require a certain prefix. This is currently done for the following properties: 1852 1853 * `appearance: *;` => `-webkit-appearance: *; -moz-appearance: *;` 1854 * `backdrop-filter: *;` => `-webkit-backdrop-filter: *;` 1855 * `background-clip: text` => `-webkit-background-clip: text;` 1856 * `box-decoration-break: *;` => `-webkit-box-decoration-break: *;` 1857 * `clip-path: *;` => `-webkit-clip-path: *;` 1858 * `font-kerning: *;` => `-webkit-font-kerning: *;` 1859 * `hyphens: *;` => `-webkit-hyphens: *;` 1860 * `initial-letter: *;` => `-webkit-initial-letter: *;` 1861 * `mask-image: *;` => `-webkit-mask-image: *;` 1862 * `mask-origin: *;` => `-webkit-mask-origin: *;` 1863 * `mask-position: *;` => `-webkit-mask-position: *;` 1864 * `mask-repeat: *;` => `-webkit-mask-repeat: *;` 1865 * `mask-size: *;` => `-webkit-mask-size: *;` 1866 * `position: sticky;` => `position: -webkit-sticky;` 1867 * `print-color-adjust: *;` => `-webkit-print-color-adjust: *;` 1868 * `tab-size: *;` => `-moz-tab-size: *; -o-tab-size: *;` 1869 * `text-decoration-color: *;` => `-webkit-text-decoration-color: *; -moz-text-decoration-color: *;` 1870 * `text-decoration-line: *;` => `-webkit-text-decoration-line: *; -moz-text-decoration-line: *;` 1871 * `text-decoration-skip: *;` => `-webkit-text-decoration-skip: *;` 1872 * `text-emphasis-color: *;` => `-webkit-text-emphasis-color: *;` 1873 * `text-emphasis-position: *;` => `-webkit-text-emphasis-position: *;` 1874 * `text-emphasis-style: *;` => `-webkit-text-emphasis-style: *;` 1875 * `text-orientation: *;` => `-webkit-text-orientation: *;` 1876 * `text-size-adjust: *;` => `-webkit-text-size-adjust: *; -ms-text-size-adjust: *;` 1877 * `user-select: *;` => `-webkit-user-select: *; -moz-user-select: *; -ms-user-select: *;` 1878 1879 Here is an example: 1880 1881 ```css 1882 /* Original code */ 1883 div { 1884 mask-image: url(x.png); 1885 } 1886 1887 /* Old output (with --target=chrome99) */ 1888 div { 1889 mask-image: url(x.png); 1890 } 1891 1892 /* New output (with --target=chrome99) */ 1893 div { 1894 -webkit-mask-image: url(x.png); 1895 mask-image: url(x.png); 1896 } 1897 ``` 1898 1899 Browser compatibility data was sourced from the tables on https://caniuse.com. Support for more CSS properties can be added in the future as appropriate. 1900 1901 * Fix an obscure identifier minification bug ([#2809](https://github.com/evanw/esbuild/issues/2809)) 1902 1903 Function declarations in nested scopes behave differently depending on whether or not `"use strict"` is present. To avoid generating code that behaves differently depending on whether strict mode is enabled or not, esbuild transforms nested function declarations into variable declarations. However, there was a bug where the generated variable name was not being recorded as declared internally, which meant that it wasn't being renamed correctly by the minifier and could cause a name collision. This bug has been fixed: 1904 1905 ```js 1906 // Original code 1907 const n = '' 1908 for (let i of [0,1]) { 1909 function f () {} 1910 } 1911 1912 // Old output (with --minify-identifiers --format=esm) 1913 const f = ""; 1914 for (let o of [0, 1]) { 1915 let n = function() { 1916 }; 1917 var f = n; 1918 } 1919 1920 // New output (with --minify-identifiers --format=esm) 1921 const f = ""; 1922 for (let o of [0, 1]) { 1923 let n = function() { 1924 }; 1925 var t = n; 1926 } 1927 ``` 1928 1929 * Fix a bug in esbuild's compatibility table script ([#3179](https://github.com/evanw/esbuild/pull/3179)) 1930 1931 Setting esbuild's `target` to a specific JavaScript engine tells esbuild to use the JavaScript syntax feature compatibility data from https://kangax.github.io/compat-table/es6/ for that engine to determine which syntax features to allow. However, esbuild's script that builds this internal compatibility table had a bug that incorrectly ignores tests for engines that still have outstanding implementation bugs which were never fixed. This change fixes this bug with the script. 1932 1933 The only case where this changed the information in esbuild's internal compatibility table is that the `hermes` target is marked as no longer supporting destructuring. This is because there is a failing destructuring-related test for Hermes on https://kangax.github.io/compat-table/es6/. If you want to use destructuring with Hermes anyway, you can pass `--supported:destructuring=true` to esbuild to override the `hermes` target and force esbuild to accept this syntax. 1934 1935 This fix was contributed by [@ArrayZoneYour](https://github.com/ArrayZoneYour). 1936 1937 ## 0.18.8 1938 1939 * Implement transforming `async` generator functions ([#2780](https://github.com/evanw/esbuild/issues/2780)) 1940 1941 With this release, esbuild will now transform `async` generator functions into normal generator functions when the configured target environment doesn't support them. These functions behave similar to normal generator functions except that they use the `Symbol.asyncIterator` interface instead of the `Symbol.iterator` interface and the iteration methods return promises. Here's an example (helper functions are omitted): 1942 1943 ```js 1944 // Original code 1945 async function* foo() { 1946 yield Promise.resolve(1) 1947 await new Promise(r => setTimeout(r, 100)) 1948 yield *[Promise.resolve(2)] 1949 } 1950 async function bar() { 1951 for await (const x of foo()) { 1952 console.log(x) 1953 } 1954 } 1955 bar() 1956 1957 // New output (with --target=es6) 1958 function foo() { 1959 return __asyncGenerator(this, null, function* () { 1960 yield Promise.resolve(1); 1961 yield new __await(new Promise((r) => setTimeout(r, 100))); 1962 yield* __yieldStar([Promise.resolve(2)]); 1963 }); 1964 } 1965 function bar() { 1966 return __async(this, null, function* () { 1967 try { 1968 for (var iter = __forAwait(foo()), more, temp, error; more = !(temp = yield iter.next()).done; more = false) { 1969 const x = temp.value; 1970 console.log(x); 1971 } 1972 } catch (temp) { 1973 error = [temp]; 1974 } finally { 1975 try { 1976 more && (temp = iter.return) && (yield temp.call(iter)); 1977 } finally { 1978 if (error) 1979 throw error[0]; 1980 } 1981 } 1982 }); 1983 } 1984 bar(); 1985 ``` 1986 1987 This is an older feature that was added to JavaScript in ES2018 but I didn't implement the transformation then because it's a rarely-used feature. Note that esbuild already added support for transforming `for await` loops (the other part of the [asynchronous iteration proposal](https://github.com/tc39/proposal-async-iteration)) a year ago, so support for asynchronous iteration should now be complete. 1988 1989 I have never used this feature myself and code that uses this feature is hard to come by, so this transformation has not yet been tested on real-world code. If you do write code that uses this feature, please let me know if esbuild's `async` generator transformation doesn't work with your code. 1990 1991 ## 0.18.7 1992 1993 * Add support for `using` declarations in TypeScript 5.2+ ([#3191](https://github.com/evanw/esbuild/issues/3191)) 1994 1995 TypeScript 5.2 (due to be released in August of 2023) will introduce `using` declarations, which will allow you to automatically dispose of the declared resources when leaving the current scope. You can read the [TypeScript PR for this feature](https://github.com/microsoft/TypeScript/pull/54505) for more information. This release of esbuild adds support for transforming this syntax to target environments without support for `using` declarations (which is currently all targets other than `esnext`). Here's an example (helper functions are omitted): 1996 1997 ```js 1998 // Original code 1999 class Foo { 2000 [Symbol.dispose]() { 2001 console.log('cleanup') 2002 } 2003 } 2004 using foo = new Foo; 2005 foo.bar(); 2006 2007 // New output (with --target=es6) 2008 var _stack = []; 2009 try { 2010 var Foo = class { 2011 [Symbol.dispose]() { 2012 console.log("cleanup"); 2013 } 2014 }; 2015 var foo = __using(_stack, new Foo()); 2016 foo.bar(); 2017 } catch (_) { 2018 var _error = _, _hasError = true; 2019 } finally { 2020 __callDispose(_stack, _error, _hasError); 2021 } 2022 ``` 2023 2024 The injected helper functions ensure that the method named `Symbol.dispose` is called on `new Foo` when control exits the scope. Note that as with all new JavaScript APIs, you'll need to polyfill `Symbol.dispose` if it's not present before you use it. This is not something that esbuild does for you because esbuild only handles syntax, not APIs. Polyfilling it can be done with something like this: 2025 2026 ```js 2027 Symbol.dispose ||= Symbol('Symbol.dispose') 2028 ``` 2029 2030 This feature also introduces `await using` declarations which are like `using` declarations but they call `await` on the disposal method (not on the initializer). Here's an example (helper functions are omitted): 2031 2032 ```js 2033 // Original code 2034 class Foo { 2035 async [Symbol.asyncDispose]() { 2036 await new Promise(done => { 2037 setTimeout(done, 1000) 2038 }) 2039 console.log('cleanup') 2040 } 2041 } 2042 await using foo = new Foo; 2043 foo.bar(); 2044 2045 // New output (with --target=es2022) 2046 var _stack = []; 2047 try { 2048 var Foo = class { 2049 async [Symbol.asyncDispose]() { 2050 await new Promise((done) => { 2051 setTimeout(done, 1e3); 2052 }); 2053 console.log("cleanup"); 2054 } 2055 }; 2056 var foo = __using(_stack, new Foo(), true); 2057 foo.bar(); 2058 } catch (_) { 2059 var _error = _, _hasError = true; 2060 } finally { 2061 var _promise = __callDispose(_stack, _error, _hasError); 2062 _promise && await _promise; 2063 } 2064 ``` 2065 2066 The injected helper functions ensure that the method named `Symbol.asyncDispose` is called on `new Foo` when control exits the scope, and that the returned promise is awaited. Similarly to `Symbol.dispose`, you'll also need to polyfill `Symbol.asyncDispose` before you use it. 2067 2068 * Add a `--line-limit=` flag to limit line length ([#3170](https://github.com/evanw/esbuild/issues/3170)) 2069 2070 Long lines are common in minified code. However, many tools and text editors can't handle long lines. This release introduces the `--line-limit=` flag to tell esbuild to wrap lines longer than the provided number of bytes. For example, `--line-limit=80` tells esbuild to insert a newline soon after a given line reaches 80 bytes in length. This setting applies to both JavaScript and CSS, and works even when minification is disabled. Note that turning this setting on will make your files bigger, as the extra newlines take up additional space in the file (even after gzip compression). 2071 2072 ## 0.18.6 2073 2074 * Fix tree-shaking of classes with decorators ([#3164](https://github.com/evanw/esbuild/issues/3164)) 2075 2076 This release fixes a bug where esbuild incorrectly allowed tree-shaking on classes with decorators. Each decorator is a function call, so classes with decorators must never be tree-shaken. This bug was a regression that was unintentionally introduced in version 0.18.2 by the change that enabled tree-shaking of lowered private fields. Previously decorators were always lowered, and esbuild always considered the automatically-generated decorator code to be a side effect. But this is no longer the case now that esbuild analyzes side effects using the AST before lowering takes place. This bug was fixed by considering any decorator a side effect. 2077 2078 * Fix a minification bug involving function expressions ([#3125](https://github.com/evanw/esbuild/issues/3125)) 2079 2080 When minification is enabled, esbuild does limited inlining of `const` symbols at the top of a scope. This release fixes a bug where inlineable symbols were incorrectly removed assuming that they were inlined. They may not be inlined in cases where they were referenced by earlier constants in the body of a function expression. The declarations involved in these edge cases are now kept instead of being removed: 2081 2082 ```js 2083 // Original code 2084 { 2085 const fn = () => foo 2086 const foo = 123 2087 console.log(fn) 2088 } 2089 2090 // Old output (with --minify-syntax) 2091 console.log((() => foo)()); 2092 2093 // New output (with --minify-syntax) 2094 { 2095 const fn = () => foo, foo = 123; 2096 console.log(fn); 2097 } 2098 ``` 2099 2100 ## 0.18.5 2101 2102 * Implement auto accessors ([#3009](https://github.com/evanw/esbuild/issues/3009)) 2103 2104 This release implements the new auto-accessor syntax from the upcoming [JavaScript decorators proposal](https://github.com/tc39/proposal-decorators). The auto-accessor syntax looks like this: 2105 2106 ```js 2107 class Foo { 2108 accessor foo; 2109 static accessor bar; 2110 } 2111 new Foo().foo = Foo.bar; 2112 ``` 2113 2114 This syntax is not yet a part of JavaScript but it was [added to TypeScript in version 4.9](https://devblogs.microsoft.com/typescript/announcing-typescript-4-9/#auto-accessors-in-classes). More information about this feature can be found in [microsoft/TypeScript#49705](https://github.com/microsoft/TypeScript/pull/49705). Auto-accessors will be transformed if the target is set to something other than `esnext`: 2115 2116 ```js 2117 // Output (with --target=esnext) 2118 class Foo { 2119 accessor foo; 2120 static accessor bar; 2121 } 2122 new Foo().foo = Foo.bar; 2123 2124 // Output (with --target=es2022) 2125 class Foo { 2126 #foo; 2127 get foo() { 2128 return this.#foo; 2129 } 2130 set foo(_) { 2131 this.#foo = _; 2132 } 2133 static #bar; 2134 static get bar() { 2135 return this.#bar; 2136 } 2137 static set bar(_) { 2138 this.#bar = _; 2139 } 2140 } 2141 new Foo().foo = Foo.bar; 2142 2143 // Output (with --target=es2021) 2144 var _foo, _bar; 2145 class Foo { 2146 constructor() { 2147 __privateAdd(this, _foo, void 0); 2148 } 2149 get foo() { 2150 return __privateGet(this, _foo); 2151 } 2152 set foo(_) { 2153 __privateSet(this, _foo, _); 2154 } 2155 static get bar() { 2156 return __privateGet(this, _bar); 2157 } 2158 static set bar(_) { 2159 __privateSet(this, _bar, _); 2160 } 2161 } 2162 _foo = new WeakMap(); 2163 _bar = new WeakMap(); 2164 __privateAdd(Foo, _bar, void 0); 2165 new Foo().foo = Foo.bar; 2166 ``` 2167 2168 You can also now use auto-accessors with esbuild's TypeScript experimental decorator transformation, which should behave the same as decorating the underlying getter/setter pair. 2169 2170 **Please keep in mind that this syntax is not yet part of JavaScript.** This release enables auto-accessors in `.js` files with the expectation that it will be a part of JavaScript soon. However, esbuild may change or remove this feature in the future if JavaScript ends up changing or removing this feature. Use this feature with caution for now. 2171 2172 * Pass through JavaScript decorators ([#104](https://github.com/evanw/esbuild/issues/104)) 2173 2174 In this release, esbuild now parses decorators from the upcoming [JavaScript decorators proposal](https://github.com/tc39/proposal-decorators) and passes them through to the output unmodified (as long as the language target is set to `esnext`). Transforming JavaScript decorators to environments that don't support them has not been implemented yet. The only decorator transform that esbuild currently implements is still the TypeScript experimental decorator transform, which only works in `.ts` files and which requires `"experimentalDecorators": true` in your `tsconfig.json` file. 2175 2176 * Static fields with assign semantics now use static blocks if possible 2177 2178 Setting `useDefineForClassFields` to false in TypeScript requires rewriting class fields to assignment statements. Previously this was done by removing the field from the class body and adding an assignment statement after the class declaration. However, this also caused any private fields to also be lowered by necessity (in case a field initializer uses a private symbol, either directly or indirectly). This release changes this transform to use an inline static block if it's supported, which avoids needing to lower private fields in this scenario: 2179 2180 ```js 2181 // Original code 2182 class Test { 2183 static #foo = 123 2184 static bar = this.#foo 2185 } 2186 2187 // Old output (with useDefineForClassFields=false) 2188 var _foo; 2189 const _Test = class _Test { 2190 }; 2191 _foo = new WeakMap(); 2192 __privateAdd(_Test, _foo, 123); 2193 _Test.bar = __privateGet(_Test, _foo); 2194 let Test = _Test; 2195 2196 // New output (with useDefineForClassFields=false) 2197 class Test { 2198 static #foo = 123; 2199 static { 2200 this.bar = this.#foo; 2201 } 2202 } 2203 ``` 2204 2205 * Fix TypeScript experimental decorators combined with `--mangle-props` ([#3177](https://github.com/evanw/esbuild/issues/3177)) 2206 2207 Previously using TypeScript experimental decorators combined with the `--mangle-props` setting could result in a crash, as the experimental decorator transform was not expecting a mangled property as a class member. This release fixes the crash so you can now combine both of these features together safely. 2208 2209 ## 0.18.4 2210 2211 * Bundling no longer unnecessarily transforms class syntax ([#1360](https://github.com/evanw/esbuild/issues/1360), [#1328](https://github.com/evanw/esbuild/issues/1328), [#1524](https://github.com/evanw/esbuild/issues/1524), [#2416](https://github.com/evanw/esbuild/issues/2416)) 2212 2213 When bundling, esbuild automatically converts top-level class statements to class expressions. Previously this conversion had the unfortunate side-effect of also transforming certain other class-related syntax features to avoid correctness issues when the references to the class name within the class body. This conversion has been reworked to avoid doing this: 2214 2215 ```js 2216 // Original code 2217 export class Foo { 2218 static foo = () => Foo 2219 } 2220 2221 // Old output (with --bundle) 2222 var _Foo = class { 2223 }; 2224 var Foo = _Foo; 2225 __publicField(Foo, "foo", () => _Foo); 2226 2227 // New output (with --bundle) 2228 var Foo = class _Foo { 2229 static foo = () => _Foo; 2230 }; 2231 ``` 2232 2233 This conversion process is very complicated and has many edge cases (including interactions with static fields, static blocks, private class properties, and TypeScript experimental decorators). It should already be pretty robust but a change like this may introduce new unintentional behavior. Please report any issues with this upgrade on the esbuild bug tracker. 2234 2235 You may be wondering why esbuild needs to do this at all. One reason to do this is that esbuild's bundler sometimes needs to lazily-evaluate a module. For example, a module may end up being both the target of a dynamic `import()` call and a static `import` statement. Lazy module evaluation is done by wrapping the top-level module code in a closure. To avoid a performance hit for static `import` statements, esbuild stores top-level exported symbols outside of the closure and references them directly instead of indirectly. 2236 2237 Another reason to do this is that multiple JavaScript VMs have had and continue to have performance issues with TDZ (i.e. "temporal dead zone") checks. These checks validate that a let, or const, or class symbol isn't used before it's initialized. Here are two issues with well-known VMs: 2238 2239 * V8: https://bugs.chromium.org/p/v8/issues/detail?id=13723 (10% slowdown) 2240 * JavaScriptCore: https://bugs.webkit.org/show_bug.cgi?id=199866 (1,000% slowdown!) 2241 2242 JavaScriptCore had a severe performance issue as their TDZ implementation had time complexity that was quadratic in the number of variables needing TDZ checks in the same scope (with the top-level scope typically being the worst offender). V8 has ongoing issues with TDZ checks being present throughout the code their JIT generates even when they have already been checked earlier in the same function or when the function in question has already been run (so the checks have already happened). 2243 2244 Due to esbuild's parallel architecture, esbuild both a) needs to convert class statements into class expressions during parsing and b) doesn't yet know whether this module will need to be lazily-evaluated or not in the parser. So esbuild always does this conversion during bundling in case it's needed for correctness (and also to avoid potentially catastrophic performance issues due to bundling creating a large scope with many TDZ variables). 2245 2246 * Enforce TDZ errors in computed class property keys ([#2045](https://github.com/evanw/esbuild/issues/2045)) 2247 2248 JavaScript allows class property keys to be generated at run-time using code, like this: 2249 2250 ```js 2251 class Foo { 2252 static foo = 'foo' 2253 static [Foo.foo + '2'] = 2 2254 } 2255 ``` 2256 2257 Previously esbuild treated references to the containing class name within computed property keys as a reference to the partially-initialized class object. That meant code that attempted to reference properties of the class object (such as the code above) would get back `undefined` instead of throwing an error. 2258 2259 This release rewrites references to the containing class name within computed property keys into code that always throws an error at run-time, which is how this JavaScript code is supposed to work. Code that does this will now also generate a warning. You should never write code like this, but it now should be more obvious when incorrect code like this is written. 2260 2261 * Fix an issue with experimental decorators and static fields ([#2629](https://github.com/evanw/esbuild/issues/2629)) 2262 2263 This release also fixes a bug regarding TypeScript experimental decorators and static class fields which reference the enclosing class name in their initializer. This affected top-level classes when bundling was enabled. Previously code that does this could crash because the class name wasn't initialized yet. This case should now be handled correctly: 2264 2265 ```ts 2266 // Original code 2267 class Foo { 2268 @someDecorator 2269 static foo = 'foo' 2270 static bar = Foo.foo.length 2271 } 2272 2273 // Old output 2274 const _Foo = class { 2275 static foo = "foo"; 2276 static bar = _Foo.foo.length; 2277 }; 2278 let Foo = _Foo; 2279 __decorateClass([ 2280 someDecorator 2281 ], Foo, "foo", 2); 2282 2283 // New output 2284 const _Foo = class _Foo { 2285 static foo = "foo"; 2286 static bar = _Foo.foo.length; 2287 }; 2288 __decorateClass([ 2289 someDecorator 2290 ], _Foo, "foo", 2); 2291 let Foo = _Foo; 2292 ``` 2293 2294 * Fix a minification regression with negative numeric properties ([#3169](https://github.com/evanw/esbuild/issues/3169)) 2295 2296 Version 0.18.0 introduced a regression where computed properties with negative numbers were incorrectly shortened into a non-computed property when minification was enabled. This regression has been fixed: 2297 2298 ```js 2299 // Original code 2300 x = { 2301 [1]: 1, 2302 [-1]: -1, 2303 [NaN]: NaN, 2304 [Infinity]: Infinity, 2305 [-Infinity]: -Infinity, 2306 } 2307 2308 // Old output (with --minify) 2309 x={1:1,-1:-1,NaN:NaN,1/0:1/0,-1/0:-1/0}; 2310 2311 // New output (with --minify) 2312 x={1:1,[-1]:-1,NaN:NaN,[1/0]:1/0,[-1/0]:-1/0}; 2313 ``` 2314 2315 ## 0.18.3 2316 2317 * Fix a panic due to empty static class blocks ([#3161](https://github.com/evanw/esbuild/issues/3161)) 2318 2319 This release fixes a bug where an internal invariant that was introduced in the previous release was sometimes violated, which then caused a panic. It happened when bundling code containing an empty static class block with both minification and bundling enabled. 2320 2321 ## 0.18.2 2322 2323 * Lower static blocks when static fields are lowered ([#2800](https://github.com/evanw/esbuild/issues/2800), [#2950](https://github.com/evanw/esbuild/issues/2950), [#3025](https://github.com/evanw/esbuild/issues/3025)) 2324 2325 This release fixes a bug where esbuild incorrectly did not lower static class blocks when static class fields needed to be lowered. For example, the following code should print `1 2 3` but previously printed `2 1 3` instead due to this bug: 2326 2327 ```js 2328 // Original code 2329 class Foo { 2330 static x = console.log(1) 2331 static { console.log(2) } 2332 static y = console.log(3) 2333 } 2334 2335 // Old output (with --supported:class-static-field=false) 2336 class Foo { 2337 static { 2338 console.log(2); 2339 } 2340 } 2341 __publicField(Foo, "x", console.log(1)); 2342 __publicField(Foo, "y", console.log(3)); 2343 2344 // New output (with --supported:class-static-field=false) 2345 class Foo { 2346 } 2347 __publicField(Foo, "x", console.log(1)); 2348 console.log(2); 2349 __publicField(Foo, "y", console.log(3)); 2350 ``` 2351 2352 * Use static blocks to implement `--keep-names` on classes ([#2389](https://github.com/evanw/esbuild/issues/2389)) 2353 2354 This change fixes a bug where the `name` property could previously be incorrect within a class static context when using `--keep-names`. The problem was that the `name` property was being initialized after static blocks were run instead of before. This has been fixed by moving the `name` property initializer into a static block at the top of the class body: 2355 2356 ```js 2357 // Original code 2358 if (typeof Foo === 'undefined') { 2359 let Foo = class { 2360 static test = this.name 2361 } 2362 console.log(Foo.test) 2363 } 2364 2365 // Old output (with --keep-names) 2366 if (typeof Foo === "undefined") { 2367 let Foo2 = /* @__PURE__ */ __name(class { 2368 static test = this.name; 2369 }, "Foo"); 2370 console.log(Foo2.test); 2371 } 2372 2373 // New output (with --keep-names) 2374 if (typeof Foo === "undefined") { 2375 let Foo2 = class { 2376 static { 2377 __name(this, "Foo"); 2378 } 2379 static test = this.name; 2380 }; 2381 console.log(Foo2.test); 2382 } 2383 ``` 2384 2385 This change was somewhat involved, especially regarding what esbuild considers to be side-effect free. Some unused classes that weren't removed by tree shaking in previous versions of esbuild may now be tree-shaken. One example is classes with static private fields that are transformed by esbuild into code that doesn't use JavaScript's private field syntax. Previously esbuild's tree shaking analysis ran on the class after syntax lowering, but with this release it will run on the class before syntax lowering, meaning it should no longer be confused by class mutations resulting from automatically-generated syntax lowering code. 2386 2387 ## 0.18.1 2388 2389 * Fill in `null` entries in input source maps ([#3144](https://github.com/evanw/esbuild/issues/3144)) 2390 2391 If esbuild bundles input files with source maps and those source maps contain a `sourcesContent` array with `null` entries, esbuild previously copied those `null` entries over to the output source map. With this release, esbuild will now attempt to fill in those `null` entries by looking for a file on the file system with the corresponding name from the `sources` array. This matches esbuild's existing behavior that automatically generates the `sourcesContent` array from the file system if the entire `sourcesContent` array is missing. 2392 2393 * Support `/* @__KEY__ */` comments for mangling property names ([#2574](https://github.com/evanw/esbuild/issues/2574)) 2394 2395 Property mangling is an advanced feature that enables esbuild to minify certain property names, even though it's not possible to automatically determine that it's safe to do so. The safe property names are configured via regular expression such as `--mangle-props=_$` (mangle all properties ending in `_`). 2396 2397 Sometimes it's desirable to also minify strings containing property names, even though it's not possible to automatically determine which strings are property names. This release makes it possible to do this by annotating those strings with `/* @__KEY__ */`. This is a convention that Terser added earlier this year, and which esbuild is now following too: https://github.com/terser/terser/pull/1365. Using it looks like this: 2398 2399 ```js 2400 // Original code 2401 console.log( 2402 [obj.mangle_, obj.keep], 2403 [obj.get('mangle_'), obj.get('keep')], 2404 [obj.get(/* @__KEY__ */ 'mangle_'), obj.get(/* @__KEY__ */ 'keep')], 2405 ) 2406 2407 // Old output (with --mangle-props=_$) 2408 console.log( 2409 [obj.a, obj.keep], 2410 [obj.get("mangle_"), obj.get("keep")], 2411 [obj.get(/* @__KEY__ */ "mangle_"), obj.get(/* @__KEY__ */ "keep")] 2412 ); 2413 2414 // New output (with --mangle-props=_$) 2415 console.log( 2416 [obj.a, obj.keep], 2417 [obj.get("mangle_"), obj.get("keep")], 2418 [obj.get(/* @__KEY__ */ "a"), obj.get(/* @__KEY__ */ "keep")] 2419 ); 2420 ``` 2421 2422 * Support `/* @__NO_SIDE_EFFECTS__ */` comments for functions ([#3149](https://github.com/evanw/esbuild/issues/3149)) 2423 2424 Rollup has recently added support for `/* @__NO_SIDE_EFFECTS__ */` annotations before functions to indicate that calls to these functions can be removed if the result is unused (i.e. the calls can be assumed to have no side effects). This release adds basic support for these to esbuild as well, which means esbuild will now parse these comments in input files and preserve them in output files. This should help people that use esbuild in combination with Rollup. 2425 2426 Note that this doesn't necessarily mean esbuild will treat these calls as having no side effects, as esbuild's parallel architecture currently isn't set up to enable this type of cross-file tree-shaking information (tree-shaking decisions regarding a function call are currently local to the file they appear in). If you want esbuild to consider a function call to have no side effects, make sure you continue to annotate the function call with `/* @__PURE__ */` (which is the previously-established convention for communicating this). 2427 2428 ## 0.18.0 2429 2430 **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.17.0` or `~0.17.0`. See npm's documentation about [semver](https://docs.npmjs.com/cli/v6/using-npm/semver/) for more information. 2431 2432 The breaking changes in this release mainly focus on fixing some long-standing issues with esbuild's handling of `tsconfig.json` files. Here are all the changes in this release, in detail: 2433 2434 * Add a way to try esbuild online ([#797](https://github.com/evanw/esbuild/issues/797)) 2435 2436 There is now a way to try esbuild live on esbuild's website without installing it: https://esbuild.github.io/try/. In addition to being able to more easily evaluate esbuild, this should also make it more efficient to generate esbuild bug reports. For example, you can use it to compare the behavior of different versions of esbuild on the same input. The state of the page is stored in the URL for easy sharing. Many thanks to [@hyrious](https://github.com/hyrious) for creating https://hyrious.me/esbuild-repl/, which was the main inspiration for this addition to esbuild's website. 2437 2438 Two forms of build options are supported: either CLI-style ([example](https://esbuild.github.io/try/#dAAwLjE3LjE5AC0tbG9hZGVyPXRzeCAtLW1pbmlmeSAtLXNvdXJjZW1hcABsZXQgZWw6IEpTWC5FbGVtZW50ID0gPGRpdiAvPg)) or JS-style ([example](https://esbuild.github.io/try/#dAAwLjE3LjE5AHsKICBsb2FkZXI6ICd0c3gnLAogIG1pbmlmeTogdHJ1ZSwKICBzb3VyY2VtYXA6IHRydWUsCn0AbGV0IGVsOiBKU1guRWxlbWVudCA9IDxkaXYgLz4)). Both are converted into a JS object that's passed to esbuild's WebAssembly API. The CLI-style argument parser is a custom one that simulates shell quoting rules, and the JS-style argument parser is also custom and parses a superset of JSON (basically JSON5 + regular expressions). So argument parsing is an approximate simulation of what happens for real but hopefully it should be close enough. 2439 2440 * Changes to esbuild's `tsconfig.json` support ([#3019](https://github.com/evanw/esbuild/issues/3019)): 2441 2442 This release makes the following changes to esbuild's `tsconfig.json` support: 2443 2444 * Using experimental decorators now requires `"experimentalDecorators": true` ([#104](https://github.com/evanw/esbuild/issues/104)) 2445 2446 Previously esbuild would always compile decorators in TypeScript code using TypeScript's experimental decorator transform. Now that standard JavaScript decorators are close to being finalized, esbuild will now require you to use `"experimentalDecorators": true` to do this. This new requirement makes it possible for esbuild to introduce a transform for standard JavaScript decorators in TypeScript code in the future. Such a transform has not been implemented yet, however. 2447 2448 * TypeScript's `target` no longer affects esbuild's `target` ([#2628](https://github.com/evanw/esbuild/issues/2628)) 2449 2450 Some people requested that esbuild support TypeScript's `target` setting, so support for it was added (in [version 0.12.4](https://github.com/evanw/esbuild/releases/v0.12.4)). However, esbuild supports reading from multiple `tsconfig.json` files within a single build, which opens up the possibility that different files in the build have different language targets configured. There isn't really any reason to do this and it can lead to unexpected results. So with this release, the `target` setting in `tsconfig.json` will no longer affect esbuild's own `target` setting. You will have to use esbuild's own target setting instead (which is a single, global value). 2451 2452 * TypeScript's `jsx` setting no longer causes esbuild to preserve JSX syntax ([#2634](https://github.com/evanw/esbuild/issues/2634)) 2453 2454 TypeScript has a setting called [`jsx`](https://www.typescriptlang.org/tsconfig#jsx) that controls how to transform JSX into JS. The tool-agnostic transform is called `react`, and the React-specific transform is called `react-jsx` (or `react-jsxdev`). There is also a setting called `preserve` which indicates JSX should be passed through untransformed. Previously people would run esbuild with `"jsx": "preserve"` in their `tsconfig.json` files and then be surprised when esbuild preserved their JSX. So with this release, esbuild will now ignore `"jsx": "preserve"` in `tsconfig.json` files. If you want to preserve JSX syntax with esbuild, you now have to use `--jsx=preserve`. 2455 2456 Note: Some people have suggested that esbuild's equivalent `jsx` setting override the one in `tsconfig.json`. However, some projects need to legitimately have different files within the same build use different transforms (i.e. `react` vs. `react-jsx`) and having esbuild's global `jsx` setting override `tsconfig.json` would prevent this from working. This release ignores `"jsx": "preserve"` but still allows other `jsx` values in `tsconfig.json` files to override esbuild's global `jsx` setting to keep the ability for multiple files within the same build to use different transforms. 2457 2458 * `useDefineForClassFields` behavior has changed ([#2584](https://github.com/evanw/esbuild/issues/2584), [#2993](https://github.com/evanw/esbuild/issues/2993)) 2459 2460 Class fields in TypeScript look like this (`x` is a class field): 2461 2462 ```js 2463 class Foo { 2464 x = 123 2465 } 2466 ``` 2467 2468 TypeScript has legacy behavior that uses assignment semantics instead of define semantics for class fields when [`useDefineForClassFields`](https://www.typescriptlang.org/tsconfig#useDefineForClassFields) is enabled (in which case class fields in TypeScript behave differently than they do in JavaScript, which is arguably "wrong"). 2469 2470 This legacy behavior exists because TypeScript added class fields to TypeScript before they were added to JavaScript. The TypeScript team decided to go with assignment semantics and shipped their implementation. Much later on TC39 decided to go with define semantics for class fields in JavaScript instead. This behaves differently if the base class has a setter with the same name: 2471 2472 ```js 2473 class Base { 2474 set x(_) { 2475 console.log('x:', _) 2476 } 2477 } 2478 2479 // useDefineForClassFields: false 2480 class AssignSemantics extends Base { 2481 constructor() { 2482 super() 2483 this.x = 123 2484 } 2485 } 2486 2487 // useDefineForClassFields: true 2488 class DefineSemantics extends Base { 2489 constructor() { 2490 super() 2491 Object.defineProperty(this, 'x', { value: 123 }) 2492 } 2493 } 2494 2495 console.log( 2496 new AssignSemantics().x, // Calls the setter 2497 new DefineSemantics().x // Doesn't call the setter 2498 ) 2499 ``` 2500 2501 When you run `tsc`, the value of `useDefineForClassFields` defaults to `false` when it's not specified and the `target` in `tsconfig.json` is present but earlier than `ES2022`. This sort of makes sense because the class field language feature was added in ES2022, so before ES2022 class fields didn't exist (and thus TypeScript's legacy behavior is active). However, TypeScript's `target` setting currently defaults to `ES3` which unfortunately means that the `useDefineForClassFields` setting currently defaults to false (i.e. to "wrong"). In other words if you run `tsc` with all default settings, class fields will behave incorrectly. 2502 2503 Previously esbuild tried to do what `tsc` did. That meant esbuild's version of `useDefineForClassFields` was `false` by default, and was also `false` if esbuild's `--target=` was present but earlier than `es2022`. However, TypeScript's legacy class field behavior is becoming increasingly irrelevant and people who expect class fields in TypeScript to work like they do in JavaScript are confused when they use esbuild with default settings. It's also confusing that the behavior of class fields would change if you changed the language target (even though that's exactly how TypeScript works). 2504 2505 So with this release, esbuild will now only use the information in `tsconfig.json` to determine whether `useDefineForClassFields` is true or not. Specifically `useDefineForClassFields` will be respected if present, otherwise it will be `false` if `target` is present in `tsconfig.json` and is `ES2021` or earlier, otherwise it will be `true`. Targets passed to esbuild's `--target=` setting will no longer affect `useDefineForClassFields`. 2506 2507 Note that this means different directories in your build can have different values for this setting since esbuild allows different directories to have different `tsconfig.json` files within the same build. This should let you migrate your code one directory at a time without esbuild's `--target=` setting affecting the semantics of your code. 2508 2509 * Add support for `verbatimModuleSyntax` from TypeScript 5.0 2510 2511 TypeScript 5.0 added a new option called [`verbatimModuleSyntax`](https://www.typescriptlang.org/tsconfig#verbatimModuleSyntax) that deprecates and replaces two older options, `preserveValueImports` and `importsNotUsedAsValues`. Setting `verbatimModuleSyntax` to true in `tsconfig.json` tells esbuild to not drop unused import statements. Specifically esbuild now treats `"verbatimModuleSyntax": true` as if you had specified both `"preserveValueImports": true` and `"importsNotUsedAsValues": "preserve"`. 2512 2513 * Add multiple inheritance for `tsconfig.json` from TypeScript 5.0 2514 2515 TypeScript 5.0 now allows [multiple inheritance for `tsconfig.json` files](https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/#supporting-multiple-configuration-files-in-extends). You can now pass an array of filenames via the `extends` parameter and your `tsconfig.json` will start off containing properties from all of those configuration files, in order. This release of esbuild adds support for this new TypeScript feature. 2516 2517 * Remove support for `moduleSuffixes` ([#2395](https://github.com/evanw/esbuild/issues/2395)) 2518 2519 The community has requested that esbuild remove support for TypeScript's `moduleSuffixes` feature, so it has been removed in this release. Instead you can use esbuild's `--resolve-extensions=` feature to select which module suffix you want to build with. 2520 2521 * Apply `--tsconfig=` overrides to `stdin` and virtual files ([#385](https://github.com/evanw/esbuild/issues/385), [#2543](https://github.com/evanw/esbuild/issues/2543)) 2522 2523 When you override esbuild's automatic `tsconfig.json` file detection with `--tsconfig=` to pass a specific `tsconfig.json` file, esbuild previously didn't apply these settings to source code passed via the `stdin` API option or to TypeScript files from plugins that weren't in the `file` namespace. This release changes esbuild's behavior so that settings from `tsconfig.json` also apply to these source code files as well. 2524 2525 * Support `--tsconfig-raw=` in build API calls ([#943](https://github.com/evanw/esbuild/issues/943), [#2440](https://github.com/evanw/esbuild/issues/2440)) 2526 2527 Previously if you wanted to override esbuild's automatic `tsconfig.json` file detection, you had to create a new `tsconfig.json` file and pass the file name to esbuild via the `--tsconfig=` flag. With this release, you can now optionally use `--tsconfig-raw=` instead to pass the contents of `tsconfig.json` to esbuild directly instead of passing the file name. For example, you can now use `--tsconfig-raw={"compilerOptions":{"experimentalDecorators":true}}` to enable TypeScript experimental decorators directly using a command-line flag (assuming you escape the quotes correctly using your current shell's quoting rules). The `--tsconfig-raw=` flag previously only worked with transform API calls but with this release, it now works with build API calls too. 2528 2529 * Ignore all `tsconfig.json` files in `node_modules` ([#276](https://github.com/evanw/esbuild/issues/276), [#2386](https://github.com/evanw/esbuild/issues/2386)) 2530 2531 This changes esbuild's behavior that applies `tsconfig.json` to all files in the subtree of the directory containing `tsconfig.json`. In version 0.12.7, esbuild started ignoring `tsconfig.json` files inside `node_modules` folders. The rationale is that people typically do this by mistake and that doing this intentionally is a rare use case that doesn't need to be supported. However, this change only applied to certain syntax-specific settings (e.g. `jsxFactory`) but did not apply to path resolution settings (e.g. `paths`). With this release, esbuild will now ignore all `tsconfig.json` files in `node_modules` instead of only ignoring certain settings. 2532 2533 * Ignore `tsconfig.json` when resolving paths within `node_modules` ([#2481](https://github.com/evanw/esbuild/issues/2481)) 2534 2535 Previously fields in `tsconfig.json` related to path resolution (e.g. `paths`) were respected for all files in the subtree containing that `tsconfig.json` file, even within a nested `node_modules` subdirectory. This meant that a project's `paths` settings could potentially affect any bundled packages. With this release, esbuild will no longer use `tsconfig.json` settings during path resolution inside nested `node_modules` subdirectories. 2536 2537 * Prefer `.js` over `.ts` within `node_modules` ([#3019](https://github.com/evanw/esbuild/issues/3019)) 2538 2539 The default list of implicit extensions that esbuild will try appending to import paths contains `.ts` before `.js`. This makes it possible to bundle TypeScript projects that reference other files in the project using extension-less imports (e.g. `./some-file` to load `./some-file.ts` instead of `./some-file.js`). However, this behavior is undesirable within `node_modules` directories. Some package authors publish both their original TypeScript code and their compiled JavaScript code side-by-side. In these cases, esbuild should arguably be using the compiled JavaScript files instead of the original TypeScript files because the TypeScript compilation settings for files within the package should be determined by the package author, not the user of esbuild. So with this release, esbuild will now prefer implicit `.js` extensions over `.ts` when searching for import paths within `node_modules`. 2540 2541 These changes are intended to improve esbuild's compatibility with `tsc` and reduce the number of unfortunate behaviors regarding `tsconfig.json` and esbuild. 2542 2543 * Add a workaround for bugs in Safari 16.2 and earlier ([#3072](https://github.com/evanw/esbuild/issues/3072)) 2544 2545 Safari's JavaScript parser had a bug (which has now been fixed) where at least something about unary/binary operators nested inside default arguments nested inside either a function or class expression was incorrectly considered a syntax error if that expression was the target of a property assignment. Here are some examples that trigger this Safari bug: 2546 2547 ``` 2548 ā± x(function (y = -1) {}.z = 2) 2549 SyntaxError: Left hand side of operator '=' must be a reference. 2550 2551 ā± x(class { f(y = -1) {} }.z = 2) 2552 SyntaxError: Left hand side of operator '=' must be a reference. 2553 ``` 2554 2555 It's not clear what the exact conditions are that trigger this bug. However, a workaround for this bug appears to be to post-process your JavaScript to wrap any in function and class declarations that are the direct target of a property access expression in parentheses. That's the workaround that UglifyJS applies for this issue: [mishoo/UglifyJS#2056](https://github.com/mishoo/UglifyJS/pull/2056). So that's what esbuild now does starting with this release: 2556 2557 ```js 2558 // Original code 2559 x(function (y = -1) {}.z = 2, class { f(y = -1) {} }.z = 2) 2560 2561 // Old output (with --minify --target=safari16.2) 2562 x(function(c=-1){}.z=2,class{f(c=-1){}}.z=2); 2563 2564 // New output (with --minify --target=safari16.2) 2565 x((function(c=-1){}).z=2,(class{f(c=-1){}}).z=2); 2566 ``` 2567 2568 This fix is not enabled by default. It's only enabled when `--target=` contains Safari 16.2 or earlier, such as with `--target=safari16.2`. You can also explicitly enable or disable this specific transform (called `function-or-class-property-access`) with `--supported:function-or-class-property-access=false`. 2569 2570 * Fix esbuild's TypeScript type declarations to forbid unknown properties ([#3089](https://github.com/evanw/esbuild/issues/3089)) 2571 2572 Version 0.17.0 of esbuild introduced a specific form of function overloads in the TypeScript type definitions for esbuild's API calls that looks like this: 2573 2574 ```ts 2575 interface TransformOptions { 2576 legalComments?: 'none' | 'inline' | 'eof' | 'external' 2577 } 2578 2579 interface TransformResult<ProvidedOptions extends TransformOptions = TransformOptions> { 2580 legalComments: string | (ProvidedOptions['legalComments'] extends 'external' ? never : undefined) 2581 } 2582 2583 declare function transformSync<ProvidedOptions extends TransformOptions>(input: string, options?: ProvidedOptions): TransformResult<ProvidedOptions> 2584 declare function transformSync(input: string, options?: TransformOptions): TransformResult 2585 ``` 2586 2587 This more accurately reflects how esbuild's JavaScript API behaves. The result object returned by `transformSync` only has the `legalComments` property if you pass `legalComments: 'external'`: 2588 2589 ```ts 2590 // These have type "string | undefined" 2591 transformSync('').legalComments 2592 transformSync('', { legalComments: 'eof' }).legalComments 2593 2594 // This has type "string" 2595 transformSync('', { legalComments: 'external' }).legalComments 2596 ``` 2597 2598 However, this form of function overloads unfortunately allows typos (e.g. `egalComments`) to pass the type checker without generating an error as TypeScript allows all objects with unknown properties to extend `TransformOptions`. These typos result in esbuild's API throwing an error at run-time. 2599 2600 To prevent typos during type checking, esbuild's TypeScript type definitions will now use a different form that looks like this: 2601 2602 ```ts 2603 type SameShape<Out, In extends Out> = In & { [Key in Exclude<keyof In, keyof Out>]: never } 2604 2605 interface TransformOptions { 2606 legalComments?: 'none' | 'inline' | 'eof' | 'external' 2607 } 2608 2609 interface TransformResult<ProvidedOptions extends TransformOptions = TransformOptions> { 2610 legalComments: string | (ProvidedOptions['legalComments'] extends 'external' ? never : undefined) 2611 } 2612 2613 declare function transformSync<T extends TransformOptions>(input: string, options?: SameShape<TransformOptions, T>): TransformResult<T> 2614 ``` 2615 2616 This change should hopefully not affect correct code. It should hopefully introduce type errors only for incorrect code. 2617 2618 * Fix CSS nesting transform for pseudo-elements ([#3119](https://github.com/evanw/esbuild/issues/3119)) 2619 2620 This release fixes esbuild's CSS nesting transform for pseudo-elements (e.g. `::before` and `::after`). The CSS nesting specification says that [the nesting selector does not work with pseudo-elements](https://www.w3.org/TR/css-nesting-1/#ref-for-matches-pseudo%E2%91%A0). This can be seen in the example below: esbuild does not carry the parent pseudo-element `::before` through the nesting selector `&`. However, that doesn't apply to pseudo-elements that are within the same selector. Previously esbuild had a bug where it considered pseudo-elements in both locations as invalid. This release changes esbuild to only consider those from the parent selector invalid, which should align with the specification: 2621 2622 ```css 2623 /* Original code */ 2624 a, b::before { 2625 &.c, &::after { 2626 content: 'd'; 2627 } 2628 } 2629 2630 /* Old output (with --target=chrome90) */ 2631 a:is(.c, ::after) { 2632 content: "d"; 2633 } 2634 2635 /* New output (with --target=chrome90) */ 2636 a.c, 2637 a::after { 2638 content: "d"; 2639 } 2640 ``` 2641 2642 * Forbid `&` before a type selector in nested CSS 2643 2644 The people behind the work-in-progress CSS nesting specification have very recently [decided to forbid nested CSS that looks like `&div`](https://github.com/w3c/csswg-drafts/issues/8662#issuecomment-1514977935). You will have to use either `div&` or `&:is(div)` instead. This release of esbuild has been updated to take this new change into consideration. Doing this now generates a warning. The suggested fix is slightly different depending on where in the overall selector it happened: 2645 2646 ``` 2647 ā² [WARNING] Cannot use type selector "input" directly after nesting selector "&" [css-syntax-error] 2648 2649 example.css:2:3: 2650 2 ā &input { 2651 ā ~~~~~ 2652 āµ :is(input) 2653 2654 CSS nesting syntax does not allow the "&" selector to come before a type selector. You can wrap 2655 this selector in ":is()" as a workaround. This restriction exists to avoid problems with SASS 2656 nesting, where the same syntax means something very different that has no equivalent in real CSS 2657 (appending a suffix to the parent selector). 2658 2659 ā² [WARNING] Cannot use type selector "input" directly after nesting selector "&" [css-syntax-error] 2660 2661 example.css:6:8: 2662 6 ā .form &input { 2663 ā ~~~~~~ 2664 āµ input& 2665 2666 CSS nesting syntax does not allow the "&" selector to come before a type selector. You can move 2667 the "&" to the end of this selector as a workaround. This restriction exists to avoid problems 2668 with SASS nesting, where the same syntax means something very different that has no equivalent in 2669 real CSS (appending a suffix to the parent selector). 2670 ``` 2671 2672 ## 0.17.19 2673 2674 * Fix CSS transform bugs with nested selectors that start with a combinator ([#3096](https://github.com/evanw/esbuild/issues/3096)) 2675 2676 This release fixes several bugs regarding transforming nested CSS into non-nested CSS for older browsers. The bugs were due to lack of test coverage for nested selectors with more than one compound selector where they all start with the same combinator. Here's what some problematic cases look like before and after these fixes: 2677 2678 ```css 2679 /* Original code */ 2680 .foo { 2681 > &a, 2682 > &b { 2683 color: red; 2684 } 2685 } 2686 .bar { 2687 > &a, 2688 + &b { 2689 color: green; 2690 } 2691 } 2692 2693 /* Old output (with --target=chrome90) */ 2694 .foo :is(> .fooa, > .foob) { 2695 color: red; 2696 } 2697 .bar :is(> .bara, + .barb) { 2698 color: green; 2699 } 2700 2701 /* New output (with --target=chrome90) */ 2702 .foo > :is(a.foo, b.foo) { 2703 color: red; 2704 } 2705 .bar > a.bar, 2706 .bar + b.bar { 2707 color: green; 2708 } 2709 ``` 2710 2711 * Fix bug with TypeScript parsing of instantiation expressions followed by `=` ([#3111](https://github.com/evanw/esbuild/issues/3111)) 2712 2713 This release fixes esbuild's TypeScript-to-JavaScript conversion code in the case where a potential instantiation expression is followed immediately by a `=` token (such that the trailing `>` becomes a `>=` token). Previously esbuild considered that to still be an instantiation expression, but the official TypeScript compiler considered it to be a `>=` operator instead. This release changes esbuild's interpretation to match TypeScript. This edge case currently [appears to be problematic](https://sucrase.io/#transforms=typescript&compareWithTypeScript=true&code=x%3Cy%3E%3Da%3Cb%3Cc%3E%3E()) for other TypeScript-to-JavaScript converters as well: 2714 2715 | Original code | TypeScript | esbuild 0.17.18 | esbuild 0.17.19 | Sucrase | Babel | 2716 |---|---|---|---|---|---| 2717 | `x<y>=a<b<c>>()` | `x<y>=a();` | `x=a();` | `x<y>=a();` | `x=a()` | Invalid left-hand side in assignment expression | 2718 2719 * Avoid removing unrecognized directives from the directive prologue when minifying ([#3115](https://github.com/evanw/esbuild/issues/3115)) 2720 2721 The [directive prologue](https://262.ecma-international.org/6.0/#sec-directive-prologues-and-the-use-strict-directive) in JavaScript is a sequence of top-level string expressions that come before your code. The only directives that JavaScript engines currently recognize are `use strict` and sometimes `use asm`. However, the people behind React have made up their own directive for their own custom dialect of JavaScript. Previously esbuild only preserved the `use strict` directive when minifying, although you could still write React JavaScript with esbuild using something like `--banner:js="'your directive here';"`. With this release, you can now put arbitrary directives in the entry point and esbuild will preserve them in its minified output: 2722 2723 ```js 2724 // Original code 2725 'use wtf'; console.log(123) 2726 2727 // Old output (with --minify) 2728 console.log(123); 2729 2730 // New output (with --minify) 2731 "use wtf";console.log(123); 2732 ``` 2733 2734 Note that this means esbuild will no longer remove certain stray top-level strings when minifying. This behavior is an intentional change because these stray top-level strings are actually part of the directive prologue, and could potentially have semantics assigned to them (as was the case with React). 2735 2736 * Improved minification of binary shift operators 2737 2738 With this release, esbuild's minifier will now evaluate the `<<` and `>>>` operators if the resulting code would be shorter: 2739 2740 ```js 2741 // Original code 2742 console.log(10 << 10, 10 << 20, -123 >>> 5, -123 >>> 10); 2743 2744 // Old output (with --minify) 2745 console.log(10<<10,10<<20,-123>>>5,-123>>>10); 2746 2747 // New output (with --minify) 2748 console.log(10240,10<<20,-123>>>5,4194303); 2749 ``` 2750 2751 ## 0.17.18 2752 2753 * Fix non-default JSON import error with `export {} from` ([#3070](https://github.com/evanw/esbuild/issues/3070)) 2754 2755 This release fixes a bug where esbuild incorrectly identified statements of the form `export { default as x } from "y" assert { type: "json" }` as a non-default import. The bug did not affect code of the form `import { default as x } from ...` (only code that used the `export` keyword). 2756 2757 * Fix a crash with an invalid subpath import ([#3067](https://github.com/evanw/esbuild/issues/3067)) 2758 2759 Previously esbuild could crash when attempting to generate a friendly error message for an invalid [subpath import](https://nodejs.org/api/packages.html#subpath-imports) (i.e. an import starting with `#`). This happened because esbuild originally only supported the `exports` field and the code for that error message was not updated when esbuild later added support for the `imports` field. This crash has been fixed. 2760 2761 ## 0.17.17 2762 2763 * Fix CSS nesting transform for top-level `&` ([#3052](https://github.com/evanw/esbuild/issues/3052)) 2764 2765 Previously esbuild could crash with a stack overflow when lowering CSS nesting rules with a top-level `&`, such as in the code below. This happened because esbuild's CSS nesting transform didn't handle top-level `&`, causing esbuild to inline the top-level selector into itself. This release handles top-level `&` by replacing it with [the `:scope` pseudo-class](https://drafts.csswg.org/selectors-4/#the-scope-pseudo): 2766 2767 ```css 2768 /* Original code */ 2769 &, 2770 a { 2771 .b { 2772 color: red; 2773 } 2774 } 2775 2776 /* New output (with --target=chrome90) */ 2777 :is(:scope, a) .b { 2778 color: red; 2779 } 2780 ``` 2781 2782 * Support `exports` in `package.json` for `extends` in `tsconfig.json` ([#3058](https://github.com/evanw/esbuild/issues/3058)) 2783 2784 TypeScript 5.0 added the ability to use `extends` in `tsconfig.json` to reference a path in a package whose `package.json` file contains an `exports` map that points to the correct location. This doesn't automatically work in esbuild because `tsconfig.json` affects esbuild's path resolution, so esbuild's normal path resolution logic doesn't apply. 2785 2786 This release adds support for doing this by adding some additional code that attempts to resolve the `extends` path using the `exports` field. The behavior should be similar enough to esbuild's main path resolution logic to work as expected. 2787 2788 Note that esbuild always treats this `extends` import as a `require()` import since that's what TypeScript appears to do. Specifically the `require` condition will be active and the `import` condition will be inactive. 2789 2790 * Fix watch mode with `NODE_PATH` ([#3062](https://github.com/evanw/esbuild/issues/3062)) 2791 2792 Node has a rarely-used feature where you can extend the set of directories that node searches for packages using the `NODE_PATH` environment variable. While esbuild supports this too, previously a bug prevented esbuild's watch mode from picking up changes to imported files that were contained directly in a `NODE_PATH` directory. You're supposed to use `NODE_PATH` for packages, but some people abuse this feature by putting files in that directory instead (e.g. `node_modules/some-file.js` instead of `node_modules/some-pkg/some-file.js`). The watch mode bug happens when you do this because esbuild first tries to read `some-file.js` as a directory and then as a file. Watch mode was incorrectly waiting for `some-file.js` to become a valid directory. This release fixes this edge case bug by changing watch mode to watch `some-file.js` as a file when this happens. 2793 2794 ## 0.17.16 2795 2796 * Fix CSS nesting transform for triple-nested rules that start with a combinator ([#3046](https://github.com/evanw/esbuild/issues/3046)) 2797 2798 This release fixes a bug with esbuild where triple-nested CSS rules that start with a combinator were not transformed correctly for older browsers. Here's an example of such a case before and after this bug fix: 2799 2800 ```css 2801 /* Original input */ 2802 .a { 2803 color: red; 2804 > .b { 2805 color: green; 2806 > .c { 2807 color: blue; 2808 } 2809 } 2810 } 2811 2812 /* Old output (with --target=chrome90) */ 2813 .a { 2814 color: red; 2815 } 2816 .a > .b { 2817 color: green; 2818 } 2819 .a .b > .c { 2820 color: blue; 2821 } 2822 2823 /* New output (with --target=chrome90) */ 2824 .a { 2825 color: red; 2826 } 2827 .a > .b { 2828 color: green; 2829 } 2830 .a > .b > .c { 2831 color: blue; 2832 } 2833 ``` 2834 2835 * Support `--inject` with a file loaded using the `copy` loader ([#3041](https://github.com/evanw/esbuild/issues/3041)) 2836 2837 This release now allows you to use `--inject` with a file that is loaded using the `copy` loader. The `copy` loader copies the imported file to the output directory verbatim and rewrites the path in the `import` statement to point to the copied output file. When used with `--inject`, this means the injected file will be copied to the output directory as-is and a bare `import` statement for that file will be inserted in any non-copy output files that esbuild generates. 2838 2839 Note that since esbuild doesn't parse the contents of copied files, esbuild will not expose any of the export names as usable imports when you do this (in the way that esbuild's `--inject` feature is typically used). However, any side-effects that the injected file has will still occur. 2840 2841 ## 0.17.15 2842 2843 * Allow keywords as type parameter names in mapped types ([#3033](https://github.com/evanw/esbuild/issues/3033)) 2844 2845 TypeScript allows type keywords to be used as parameter names in mapped types. Previously esbuild incorrectly treated this as an error. Code that does this is now supported: 2846 2847 ```ts 2848 type Foo = 'a' | 'b' | 'c' 2849 type A = { [keyof in Foo]: number } 2850 type B = { [infer in Foo]: number } 2851 type C = { [readonly in Foo]: number } 2852 ``` 2853 2854 * Add annotations for re-exported modules in node ([#2486](https://github.com/evanw/esbuild/issues/2486), [#3029](https://github.com/evanw/esbuild/issues/3029)) 2855 2856 Node lets you import named imports from a CommonJS module using ESM import syntax. However, the allowed names aren't derived from the properties of the CommonJS module. Instead they are derived from an arbitrary syntax-only analysis of the CommonJS module's JavaScript AST. 2857 2858 To accommodate node doing this, esbuild's ESM-to-CommonJS conversion adds a special non-executable "annotation" for node that describes the exports that node should expose in this scenario. It takes the form `0 && (module.exports = { ... })` and comes at the end of the file (`0 && expr` means `expr` is never evaluated). 2859 2860 Previously esbuild didn't do this for modules re-exported using the `export * from` syntax. Annotations for these re-exports will now be added starting with this release: 2861 2862 ```js 2863 // Original input 2864 export { foo } from './foo' 2865 export * from './bar' 2866 2867 // Old output (with --format=cjs --platform=node) 2868 ... 2869 0 && (module.exports = { 2870 foo 2871 }); 2872 2873 // New output (with --format=cjs --platform=node) 2874 ... 2875 0 && (module.exports = { 2876 foo, 2877 ...require("./bar") 2878 }); 2879 ``` 2880 2881 Note that you need to specify both `--format=cjs` and `--platform=node` to get these node-specific annotations. 2882 2883 * Avoid printing an unnecessary space in between a number and a `.` ([#3026](https://github.com/evanw/esbuild/pull/3026)) 2884 2885 JavaScript typically requires a space in between a number token and a `.` token to avoid the `.` being interpreted as a decimal point instead of a member expression. However, this space is not required if the number token itself contains a decimal point, an exponent, or uses a base other than 10. This release of esbuild now avoids printing the unnecessary space in these cases: 2886 2887 ```js 2888 // Original input 2889 foo(1000 .x, 0 .x, 0.1 .x, 0.0001 .x, 0xFFFF_0000_FFFF_0000 .x) 2890 2891 // Old output (with --minify) 2892 foo(1e3 .x,0 .x,.1 .x,1e-4 .x,0xffff0000ffff0000 .x); 2893 2894 // New output (with --minify) 2895 foo(1e3.x,0 .x,.1.x,1e-4.x,0xffff0000ffff0000.x); 2896 ``` 2897 2898 * Fix server-sent events with live reload when writing to the file system root ([#3027](https://github.com/evanw/esbuild/issues/3027)) 2899 2900 This release fixes a bug where esbuild previously failed to emit server-sent events for live reload when `outdir` was the file system root, such as `/`. This happened because `/` is the only path on Unix that cannot have a trailing slash trimmed from it, which was fixed by improved path handling. 2901 2902 ## 0.17.14 2903 2904 * Allow the TypeScript 5.0 `const` modifier in object type declarations ([#3021](https://github.com/evanw/esbuild/issues/3021)) 2905 2906 The new TypeScript 5.0 `const` modifier was added to esbuild in version 0.17.5, and works with classes, functions, and arrow expressions. However, support for it wasn't added to object type declarations (e.g. interfaces) due to an oversight. This release adds support for these cases, so the following TypeScript 5.0 code can now be built with esbuild: 2907 2908 ```ts 2909 interface Foo { <const T>(): T } 2910 type Bar = { new <const T>(): T } 2911 ``` 2912 2913 * Implement preliminary lowering for CSS nesting ([#1945](https://github.com/evanw/esbuild/issues/1945)) 2914 2915 Chrome has [implemented the new CSS nesting specification](https://developer.chrome.com/articles/css-nesting/) in version 112, which is currently in beta but will become stable very soon. So CSS nesting is now a part of the web platform! 2916 2917 This release of esbuild can now transform nested CSS syntax into non-nested CSS syntax for older browsers. The transformation relies on the `:is()` pseudo-class in many cases, so the transformation is only guaranteed to work when targeting browsers that support `:is()` (e.g. Chrome 88+). You'll need to set esbuild's [`target`](https://esbuild.github.io/api/#target) to the browsers you intend to support to tell esbuild to do this transformation. You will get a warning if you use CSS nesting syntax with a `target` which includes older browsers that don't support `:is()`. 2918 2919 The lowering transformation looks like this: 2920 2921 ```css 2922 /* Original input */ 2923 a.btn { 2924 color: #333; 2925 &:hover { color: #444 } 2926 &:active { color: #555 } 2927 } 2928 2929 /* New output (with --target=chrome88) */ 2930 a.btn { 2931 color: #333; 2932 } 2933 a.btn:hover { 2934 color: #444; 2935 } 2936 a.btn:active { 2937 color: #555; 2938 } 2939 ``` 2940 2941 More complex cases may generate the `:is()` pseudo-class: 2942 2943 ```css 2944 /* Original input */ 2945 div, p { 2946 .warning, .error { 2947 padding: 20px; 2948 } 2949 } 2950 2951 /* New output (with --target=chrome88) */ 2952 :is(div, p) :is(.warning, .error) { 2953 padding: 20px; 2954 } 2955 ``` 2956 2957 In addition, esbuild now has a special warning message for nested style rules that start with an identifier. This isn't allowed in CSS because the syntax would be ambiguous with the existing declaration syntax. The new warning message looks like this: 2958 2959 ``` 2960 ā² [WARNING] A nested style rule cannot start with "p" because it looks like the start of a declaration [css-syntax-error] 2961 2962 <stdin>:1:7: 2963 1 ā main { p { margin: auto } } 2964 ā ^ 2965 āµ :is(p) 2966 2967 To start a nested style rule with an identifier, you need to wrap the identifier in ":is(...)" to 2968 prevent the rule from being parsed as a declaration. 2969 ``` 2970 2971 Keep in mind that the transformation in this release is a preliminary implementation. CSS has many features that interact in complex ways, and there may be some edge cases that don't work correctly yet. 2972 2973 * Minification now removes unnecessary `&` CSS nesting selectors 2974 2975 This release introduces the following CSS minification optimizations: 2976 2977 ```css 2978 /* Original input */ 2979 a { 2980 font-weight: bold; 2981 & { 2982 color: blue; 2983 } 2984 & :hover { 2985 text-decoration: underline; 2986 } 2987 } 2988 2989 /* Old output (with --minify) */ 2990 a{font-weight:700;&{color:#00f}& :hover{text-decoration:underline}} 2991 2992 /* New output (with --minify) */ 2993 a{font-weight:700;:hover{text-decoration:underline}color:#00f} 2994 ``` 2995 2996 * Minification now removes duplicates from CSS selector lists 2997 2998 This release introduces the following CSS minification optimization: 2999 3000 ```css 3001 /* Original input */ 3002 div, div { color: red } 3003 3004 /* Old output (with --minify) */ 3005 div,div{color:red} 3006 3007 /* New output (with --minify) */ 3008 div{color:red} 3009 ``` 3010 3011 ## 0.17.13 3012 3013 * Work around an issue with `NODE_PATH` and Go's WebAssembly internals ([#3001](https://github.com/evanw/esbuild/issues/3001)) 3014 3015 Go's WebAssembly implementation returns `EINVAL` instead of `ENOTDIR` when using the `readdir` syscall on a file. This messes up esbuild's implementation of node's module resolution algorithm since encountering `ENOTDIR` causes esbuild to continue its search (since it's a normal condition) while other encountering other errors causes esbuild to fail with an I/O error (since it's an unexpected condition). You can encounter this issue in practice if you use node's legacy `NODE_PATH` feature to tell esbuild to resolve node modules in a custom directory that was not installed by npm. This release works around this problem by converting `EINVAL` into `ENOTDIR` for the `readdir` syscall. 3016 3017 * Fix a minification bug with CSS `@layer` rules that have parsing errors ([#3016](https://github.com/evanw/esbuild/issues/3016)) 3018 3019 CSS at-rules [require either a `{}` block or a semicolon at the end](https://www.w3.org/TR/css-syntax-3/#consume-at-rule). Omitting both of these causes esbuild to treat the rule as an unknown at-rule. Previous releases of esbuild had a bug that incorrectly removed unknown at-rules without any children during minification if the at-rule token matched an at-rule that esbuild can handle. Specifically [cssnano](https://cssnano.co/) can generate `@layer` rules with parsing errors, and empty `@layer` rules cannot be removed because they have side effects (`@layer` didn't exist when esbuild's CSS support was added, so esbuild wasn't written to handle this). This release changes esbuild to no longer discard `@layer` rules with parsing errors when minifying (the rule `@layer c` has a parsing error): 3020 3021 ```css 3022 /* Original input */ 3023 @layer a { 3024 @layer b { 3025 @layer c 3026 } 3027 } 3028 3029 /* Old output (with --minify) */ 3030 @layer a.b; 3031 3032 /* New output (with --minify) */ 3033 @layer a.b.c; 3034 ``` 3035 3036 * Unterminated strings in CSS are no longer an error 3037 3038 The CSS specification provides [rules for handling parsing errors](https://www.w3.org/TR/CSS22/syndata.html#parsing-errors). One of those rules is that user agents must close strings upon reaching the end of a line (i.e., before an unescaped line feed, carriage return or form feed character), but then drop the construct (declaration or rule) in which the string was found. For example: 3039 3040 ```css 3041 p { 3042 color: green; 3043 font-family: 'Courier New Times 3044 color: red; 3045 color: green; 3046 } 3047 ``` 3048 3049 ...would be treated the same as: 3050 3051 ```css 3052 p { color: green; color: green; } 3053 ``` 3054 3055 ...because the second declaration (from `font-family` to the semicolon after `color: red`) is invalid and is dropped. 3056 3057 Previously using this CSS with esbuild failed to build due to a syntax error, even though the code can be interpreted by a browser. With this release, the code now produces a warning instead of an error, and esbuild prints the invalid CSS such that it stays invalid in the output: 3058 3059 ```css 3060 /* esbuild's new non-minified output: */ 3061 p { 3062 color: green; 3063 font-family: 'Courier New Times 3064 color: red; 3065 color: green; 3066 } 3067 ``` 3068 3069 ```css 3070 /* esbuild's new minified output: */ 3071 p{font-family:'Courier New Times 3072 color: red;color:green} 3073 ``` 3074 3075 ## 0.17.12 3076 3077 * Fix a crash when parsing inline TypeScript decorators ([#2991](https://github.com/evanw/esbuild/issues/2991)) 3078 3079 Previously esbuild's TypeScript parser crashed when parsing TypeScript decorators if the definition of the decorator was inlined into the decorator itself: 3080 3081 ```ts 3082 @(function sealed(constructor: Function) { 3083 Object.seal(constructor); 3084 Object.seal(constructor.prototype); 3085 }) 3086 class Foo {} 3087 ``` 3088 3089 This crash was not noticed earlier because this edge case did not have test coverage. The crash is fixed in this release. 3090 3091 ## 0.17.11 3092 3093 * Fix the `alias` feature to always prefer the longest match ([#2963](https://github.com/evanw/esbuild/issues/2963)) 3094 3095 It's possible to configure conflicting aliases such as `--alias:a=b` and `--alias:a/c=d`, which is ambiguous for the import path `a/c/x` (since it could map to either `b/c/x` or `d/x`). Previously esbuild would pick the first matching `alias`, which would non-deterministically pick between one of the possible matches. This release fixes esbuild to always deterministically pick the longest possible match. 3096 3097 * Minify calls to some global primitive constructors ([#2962](https://github.com/evanw/esbuild/issues/2962)) 3098 3099 With this release, esbuild's minifier now replaces calls to `Boolean`/`Number`/`String`/`BigInt` with equivalent shorter code when relevant: 3100 3101 ```js 3102 // Original code 3103 console.log( 3104 Boolean(a ? (b | c) !== 0 : (c & d) !== 0), 3105 Number(e ? '1' : '2'), 3106 String(e ? '1' : '2'), 3107 BigInt(e ? 1n : 2n), 3108 ) 3109 3110 // Old output (with --minify) 3111 console.log(Boolean(a?(b|c)!==0:(c&d)!==0),Number(e?"1":"2"),String(e?"1":"2"),BigInt(e?1n:2n)); 3112 3113 // New output (with --minify) 3114 console.log(!!(a?b|c:c&d),+(e?"1":"2"),e?"1":"2",e?1n:2n); 3115 ``` 3116 3117 * Adjust some feature compatibility tables for node ([#2940](https://github.com/evanw/esbuild/issues/2940)) 3118 3119 This release makes the following adjustments to esbuild's internal feature compatibility tables for node, which tell esbuild which versions of node are known to support all aspects of that feature: 3120 3121 * `class-private-brand-checks`: node v16.9+ => node v16.4+ (a decrease) 3122 * `hashbang`: node v12.0+ => node v12.5+ (an increase) 3123 * `optional-chain`: node v16.9+ => node v16.1+ (a decrease) 3124 * `template-literal`: node v4+ => node v10+ (an increase) 3125 3126 Each of these adjustments was identified by comparing against data from the `node-compat-table` package and was manually verified using old node executables downloaded from https://nodejs.org/download/release/. 3127 3128 ## 0.17.10 3129 3130 * Update esbuild's handling of CSS nesting to match the latest specification changes ([#1945](https://github.com/evanw/esbuild/issues/1945)) 3131 3132 The syntax for the upcoming CSS nesting feature has [recently changed](https://webkit.org/blog/13813/try-css-nesting-today-in-safari-technology-preview/). The `@nest` prefix that was previously required in some cases is now gone, and nested rules no longer have to start with `&` (as long as they don't start with an identifier or function token). 3133 3134 This release updates esbuild's pass-through handling of CSS nesting syntax to match the latest specification changes. So you can now use esbuild to bundle CSS containing nested rules and try them out in a browser that supports CSS nesting (which includes nightly builds of both Chrome and Safari). 3135 3136 However, I'm not implementing lowering of nested CSS to non-nested CSS for older browsers yet. While the syntax has been decided, the semantics are still in flux. In particular, there is still some debate about changing the fundamental way that CSS nesting works. For example, you might think that the following CSS is equivalent to a `.outer .inner button { ... }` rule: 3137 3138 ```css 3139 .inner button { 3140 .outer & { 3141 color: red; 3142 } 3143 } 3144 ``` 3145 3146 But instead it's actually equivalent to a `.outer :is(.inner button) { ... }` rule which unintuitively also matches the following DOM structure: 3147 3148 ```html 3149 <div class="inner"> 3150 <div class="outer"> 3151 <button></button> 3152 </div> 3153 </div> 3154 ``` 3155 3156 The `:is()` behavior is preferred by browser implementers because it's more memory-efficient, but the straightforward translation into a `.outer .inner button { ... }` rule is preferred by developers used to the existing CSS preprocessing ecosystem (e.g. SASS). It seems premature to commit esbuild to specific semantics for this syntax at this time given the ongoing debate. 3157 3158 * Fix cross-file CSS rule deduplication involving `url()` tokens ([#2936](https://github.com/evanw/esbuild/issues/2936)) 3159 3160 Previously cross-file CSS rule deduplication didn't handle `url()` tokens correctly. These tokens contain references to import paths which may be internal (i.e. in the bundle) or external (i.e. not in the bundle). When comparing two `url()` tokens for equality, the underlying import paths should be compared instead of their references. This release of esbuild fixes `url()` token comparisons. One side effect is that `@font-face` rules should now be deduplicated correctly across files: 3161 3162 ```css 3163 /* Original code */ 3164 @import "data:text/css, \ 3165 @import 'http://example.com/style.css'; \ 3166 @font-face { src: url(http://example.com/font.ttf) }"; 3167 @import "data:text/css, \ 3168 @font-face { src: url(http://example.com/font.ttf) }"; 3169 3170 /* Old output (with --bundle --minify) */ 3171 @import"http://example.com/style.css";@font-face{src:url(http://example.com/font.ttf)}@font-face{src:url(http://example.com/font.ttf)} 3172 3173 /* New output (with --bundle --minify) */ 3174 @import"http://example.com/style.css";@font-face{src:url(http://example.com/font.ttf)} 3175 ``` 3176 3177 ## 0.17.9 3178 3179 * Parse rest bindings in TypeScript types ([#2937](https://github.com/evanw/esbuild/issues/2937)) 3180 3181 Previously esbuild was unable to parse the following valid TypeScript code: 3182 3183 ```ts 3184 let tuple: (...[e1, e2, ...es]: any) => any 3185 ``` 3186 3187 This release includes support for parsing code like this. 3188 3189 * Fix TypeScript code translation for certain computed `declare` class fields ([#2914](https://github.com/evanw/esbuild/issues/2914)) 3190 3191 In TypeScript, the key of a computed `declare` class field should only be preserved if there are no decorators for that field. Previously esbuild always preserved the key, but esbuild will now remove the key to match the output of the TypeScript compiler: 3192 3193 ```ts 3194 // Original code 3195 declare function dec(a: any, b: any): any 3196 declare const removeMe: unique symbol 3197 declare const keepMe: unique symbol 3198 class X { 3199 declare [removeMe]: any 3200 @dec declare [keepMe]: any 3201 } 3202 3203 // Old output 3204 var _a; 3205 class X { 3206 } 3207 removeMe, _a = keepMe; 3208 __decorateClass([ 3209 dec 3210 ], X.prototype, _a, 2); 3211 3212 // New output 3213 var _a; 3214 class X { 3215 } 3216 _a = keepMe; 3217 __decorateClass([ 3218 dec 3219 ], X.prototype, _a, 2); 3220 ``` 3221 3222 * Fix a crash with path resolution error generation ([#2913](https://github.com/evanw/esbuild/issues/2913)) 3223 3224 In certain situations, a module containing an invalid import path could previously cause esbuild to crash when it attempts to generate a more helpful error message. This crash has been fixed. 3225 3226 ## 0.17.8 3227 3228 * Fix a minification bug with non-ASCII identifiers ([#2910](https://github.com/evanw/esbuild/issues/2910)) 3229 3230 This release fixes a bug with esbuild where non-ASCII identifiers followed by a keyword were incorrectly not separated by a space. This bug affected both the `in` and `instanceof` keywords. Here's an example of the fix: 3231 3232 ```js 3233 // Original code 3234 Ļ in a 3235 3236 // Old output (with --minify --charset=utf8) 3237 Ļin a; 3238 3239 // New output (with --minify --charset=utf8) 3240 Ļ in a; 3241 ``` 3242 3243 * Fix a regression with esbuild's WebAssembly API in version 0.17.6 ([#2911](https://github.com/evanw/esbuild/issues/2911)) 3244 3245 Version 0.17.6 of esbuild updated the Go toolchain to version 1.20.0. This had the unfortunate side effect of increasing the amount of stack space that esbuild uses (presumably due to some changes to Go's WebAssembly implementation) which could cause esbuild's WebAssembly-based API to crash with a stack overflow in cases where it previously didn't crash. One such case is the package `grapheme-splitter` which contains code that looks like this: 3246 3247 ```js 3248 if ( 3249 (0x0300 <= code && code <= 0x036F) || 3250 (0x0483 <= code && code <= 0x0487) || 3251 (0x0488 <= code && code <= 0x0489) || 3252 (0x0591 <= code && code <= 0x05BD) || 3253 // ... many hundreds of lines later ... 3254 ) { 3255 return; 3256 } 3257 ``` 3258 3259 This edge case involves a chain of binary operators that results in an AST over 400 nodes deep. Normally this wouldn't be a problem because Go has growable call stacks, so the call stack would just grow to be as large as needed. However, WebAssembly byte code deliberately doesn't expose the ability to manipulate the stack pointer, so Go's WebAssembly translation is forced to use the fixed-size WebAssembly call stack. So esbuild's WebAssembly implementation is vulnerable to stack overflow in cases like these. 3260 3261 It's not unreasonable for this to cause a stack overflow, and for esbuild's answer to this problem to be "don't write code like this." That's how many other AST-manipulation tools handle this problem. However, it's possible to implement AST traversal using iteration instead of recursion to work around limited call stack space. This version of esbuild implements this code transformation for esbuild's JavaScript parser and printer, so esbuild's WebAssembly implementation is now able to process the `grapheme-splitter` package (at least when compiled with Go 1.20.0 and run with node's WebAssembly implementation). 3262 3263 ## 0.17.7 3264 3265 * Change esbuild's parsing of TypeScript instantiation expressions to match TypeScript 4.8+ ([#2907](https://github.com/evanw/esbuild/issues/2907)) 3266 3267 This release updates esbuild's implementation of instantiation expression erasure to match [microsoft/TypeScript#49353](https://github.com/microsoft/TypeScript/pull/49353). The new rules are as follows (copied from TypeScript's PR description): 3268 3269 > When a potential type argument list is followed by 3270 > 3271 > * a line break, 3272 > * an `(` token, 3273 > * a template literal string, or 3274 > * any token except `<` or `>` that isn't the start of an expression, 3275 > 3276 > we consider that construct to be a type argument list. Otherwise we consider the construct to be a `<` relational expression followed by a `>` relational expression. 3277 3278 * Ignore `sideEffects: false` for imported CSS files ([#1370](https://github.com/evanw/esbuild/issues/1370), [#1458](https://github.com/evanw/esbuild/pull/1458), [#2905](https://github.com/evanw/esbuild/issues/2905)) 3279 3280 This release ignores the `sideEffects` annotation in `package.json` for CSS files that are imported into JS files using esbuild's `css` loader. This means that these CSS files are no longer be tree-shaken. 3281 3282 Importing CSS into JS causes esbuild to automatically create a CSS entry point next to the JS entry point containing the bundled CSS. Previously packages that specified some form of `"sideEffects": false` could potentially cause esbuild to consider one or more of the JS files on the import path to the CSS file to be side-effect free, which would result in esbuild removing that CSS file from the bundle. This was problematic because the removal of that CSS is outwardly observable, since all CSS is global, so it was incorrect for previous versions of esbuild to tree-shake CSS files imported into JS files. 3283 3284 * Add constant folding for certain additional equality cases ([#2394](https://github.com/evanw/esbuild/issues/2394), [#2895](https://github.com/evanw/esbuild/issues/2895)) 3285 3286 This release adds constant folding for expressions similar to the following: 3287 3288 ```js 3289 // Original input 3290 console.log( 3291 null === 'foo', 3292 null === undefined, 3293 null == undefined, 3294 false === 0, 3295 false == 0, 3296 1 === true, 3297 1 == true, 3298 ) 3299 3300 // Old output 3301 console.log( 3302 null === "foo", 3303 null === void 0, 3304 null == void 0, 3305 false === 0, 3306 false == 0, 3307 1 === true, 3308 1 == true 3309 ); 3310 3311 // New output 3312 console.log( 3313 false, 3314 false, 3315 true, 3316 false, 3317 true, 3318 false, 3319 true 3320 ); 3321 ``` 3322 3323 ## 0.17.6 3324 3325 * Fix a CSS parser crash on invalid CSS ([#2892](https://github.com/evanw/esbuild/issues/2892)) 3326 3327 Previously the following invalid CSS caused esbuild's parser to crash: 3328 3329 ```css 3330 @media screen 3331 ``` 3332 3333 The crash was caused by trying to construct a helpful error message assuming that there was an opening `{` token, which is not the case here. This release fixes the crash. 3334 3335 * Inline TypeScript enums that are referenced before their declaration 3336 3337 Previously esbuild inlined enums within a TypeScript file from top to bottom, which meant that references to TypeScript enum members were only inlined within the same file if they came after the enum declaration. With this release, esbuild will now inline enums even when they are referenced before they are declared: 3338 3339 ```ts 3340 // Original input 3341 export const foo = () => Foo.FOO 3342 const enum Foo { FOO = 0 } 3343 3344 // Old output (with --tree-shaking=true) 3345 export const foo = () => Foo.FOO; 3346 var Foo = /* @__PURE__ */ ((Foo2) => { 3347 Foo2[Foo2["FOO"] = 0] = "FOO"; 3348 return Foo2; 3349 })(Foo || {}); 3350 3351 // New output (with --tree-shaking=true) 3352 export const foo = () => 0 /* FOO */; 3353 ``` 3354 3355 This makes esbuild's TypeScript output smaller and faster when processing code that does this. I noticed this issue when I ran the TypeScript compiler's source code through esbuild's bundler. Now that the TypeScript compiler is going to be bundled with esbuild in the upcoming TypeScript 5.0 release, improvements like this will also improve the TypeScript compiler itself! 3356 3357 * Fix esbuild installation on Arch Linux ([#2785](https://github.com/evanw/esbuild/issues/2785), [#2812](https://github.com/evanw/esbuild/issues/2812), [#2865](https://github.com/evanw/esbuild/issues/2865)) 3358 3359 Someone made an unofficial `esbuild` package for Linux that adds the `ESBUILD_BINARY_PATH=/usr/bin/esbuild` environment variable to the user's default environment. This breaks all npm installations of esbuild for users with this unofficial Linux package installed, which has affected many people. Most (all?) people who encounter this problem haven't even installed this unofficial package themselves; instead it was installed for them as a dependency of another Linux package. The problematic change to add the `ESBUILD_BINARY_PATH` environment variable was reverted in the latest version of this unofficial package. However, old versions of this unofficial package are still there and will be around forever. With this release, `ESBUILD_BINARY_PATH` is now ignored by esbuild's install script when it's set to the value `/usr/bin/esbuild`. This should unbreak using npm to install `esbuild` in these problematic Linux environments. 3360 3361 Note: The `ESBUILD_BINARY_PATH` variable is an undocumented way to override the location of esbuild's binary when esbuild's npm package is installed, which is necessary to substitute your own locally-built esbuild binary when debugging esbuild's npm package. It's only meant for very custom situations and should absolutely not be forced on others by default, especially without their knowledge. I may remove the code in esbuild's installer that reads `ESBUILD_BINARY_PATH` in the future to prevent these kinds of issues. It will unfortunately make debugging esbuild harder. If `ESBUILD_BINARY_PATH` is ever removed, it will be done in a "breaking change" release. 3362 3363 ## 0.17.5 3364 3365 * Parse `const` type parameters from TypeScript 5.0 3366 3367 The TypeScript 5.0 beta announcement adds [`const` type parameters](https://devblogs.microsoft.com/typescript/announcing-typescript-5-0-beta/#const-type-parameters) to the language. You can now add the `const` modifier on a type parameter of a function, method, or class like this: 3368 3369 ```ts 3370 type HasNames = { names: readonly string[] }; 3371 const getNamesExactly = <const T extends HasNames>(arg: T): T["names"] => arg.names; 3372 const names = getNamesExactly({ names: ["Alice", "Bob", "Eve"] }); 3373 ``` 3374 3375 The type of `names` in the above example is `readonly ["Alice", "Bob", "Eve"]`. Marking the type parameter as `const` behaves as if you had written `as const` at every use instead. The above code is equivalent to the following TypeScript, which was the only option before TypeScript 5.0: 3376 3377 ```ts 3378 type HasNames = { names: readonly string[] }; 3379 const getNamesExactly = <T extends HasNames>(arg: T): T["names"] => arg.names; 3380 const names = getNamesExactly({ names: ["Alice", "Bob", "Eve"] } as const); 3381 ``` 3382 3383 You can read [the announcement](https://devblogs.microsoft.com/typescript/announcing-typescript-5-0-beta/#const-type-parameters) for more information. 3384 3385 * Make parsing generic `async` arrow functions more strict in `.tsx` files 3386 3387 Previously esbuild's TypeScript parser incorrectly accepted the following code as valid: 3388 3389 ```tsx 3390 let fn = async <T> () => {}; 3391 ``` 3392 3393 The official TypeScript parser rejects this code because it thinks it's the identifier `async` followed by a JSX element starting with `<T>`. So with this release, esbuild will now reject this syntax in `.tsx` files too. You'll now have to add a comma after the type parameter to get generic arrow functions like this to parse in `.tsx` files: 3394 3395 ```tsx 3396 let fn = async <T,> () => {}; 3397 ``` 3398 3399 * Allow the `in` and `out` type parameter modifiers on class expressions 3400 3401 TypeScript 4.7 added the `in` and `out` modifiers on the type parameters of classes, interfaces, and type aliases. However, while TypeScript supported them on both class expressions and class statements, previously esbuild only supported them on class statements due to an oversight. This release now allows these modifiers on class expressions too: 3402 3403 ```ts 3404 declare let Foo: any; 3405 Foo = class <in T> { }; 3406 Foo = class <out T> { }; 3407 ``` 3408 3409 * Update `enum` constant folding for TypeScript 5.0 3410 3411 TypeScript 5.0 contains an [updated definition of what it considers a constant expression](https://github.com/microsoft/TypeScript/pull/50528): 3412 3413 > An expression is considered a *constant expression* if it is 3414 > 3415 > * a number or string literal, 3416 > * a unary `+`, `-`, or `~` applied to a numeric constant expression, 3417 > * a binary `+`, `-`, `*`, `/`, `%`, `**`, `<<`, `>>`, `>>>`, `|`, `&`, `^` applied to two numeric constant expressions, 3418 > * a binary `+` applied to two constant expressions whereof at least one is a string, 3419 > * a template expression where each substitution expression is a constant expression, 3420 > * a parenthesized constant expression, 3421 > * a dotted name (e.g. `x.y.z`) that references a `const` variable with a constant expression initializer and no type annotation, 3422 > * a dotted name that references an enum member with an enum literal type, or 3423 > * a dotted name indexed by a string literal (e.g. `x.y["z"]`) that references an enum member with an enum literal type. 3424 3425 This impacts esbuild's implementation of TypeScript's `const enum` feature. With this release, esbuild will now attempt to follow these new rules. For example, you can now initialize an `enum` member with a template literal expression that contains a numeric constant: 3426 3427 ```ts 3428 // Original input 3429 const enum Example { 3430 COUNT = 100, 3431 ERROR = `Expected ${COUNT} items`, 3432 } 3433 console.log( 3434 Example.COUNT, 3435 Example.ERROR, 3436 ) 3437 3438 // Old output (with --tree-shaking=true) 3439 var Example = /* @__PURE__ */ ((Example2) => { 3440 Example2[Example2["COUNT"] = 100] = "COUNT"; 3441 Example2[Example2["ERROR"] = `Expected ${100 /* COUNT */} items`] = "ERROR"; 3442 return Example2; 3443 })(Example || {}); 3444 console.log( 3445 100 /* COUNT */, 3446 Example.ERROR 3447 ); 3448 3449 // New output (with --tree-shaking=true) 3450 console.log( 3451 100 /* COUNT */, 3452 "Expected 100 items" /* ERROR */ 3453 ); 3454 ``` 3455 3456 These rules are not followed exactly due to esbuild's limitations. The rule about dotted references to `const` variables is not followed both because esbuild's enum processing is done in an isolated module setting and because doing so would potentially require esbuild to use a type system, which it doesn't have. For example: 3457 3458 ```ts 3459 // The TypeScript compiler inlines this but esbuild doesn't: 3460 declare const x = 'foo' 3461 const enum Foo { X = x } 3462 console.log(Foo.X) 3463 ``` 3464 3465 Also, the rule that requires converting numbers to a string currently only followed for 32-bit signed integers and non-finite numbers. This is done to avoid accidentally introducing a bug if esbuild's number-to-string operation doesn't exactly match the behavior of a real JavaScript VM. Currently esbuild's number-to-string constant folding is conservative for safety. 3466 3467 * Forbid definite assignment assertion operators on class methods 3468 3469 In TypeScript, class methods can use the `?` optional property operator but not the `!` definite assignment assertion operator (while class fields can use both): 3470 3471 ```ts 3472 class Foo { 3473 // These are valid TypeScript 3474 a? 3475 b! 3476 x?() {} 3477 3478 // This is invalid TypeScript 3479 y!() {} 3480 } 3481 ``` 3482 3483 Previously esbuild incorrectly allowed the definite assignment assertion operator with class methods. This will no longer be allowed starting with this release. 3484 3485 ## 0.17.4 3486 3487 * Implement HTTP `HEAD` requests in serve mode ([#2851](https://github.com/evanw/esbuild/issues/2851)) 3488 3489 Previously esbuild's serve mode only responded to HTTP `GET` requests. With this release, esbuild's serve mode will also respond to HTTP `HEAD` requests, which are just like HTTP `GET` requests except that the body of the response is omitted. 3490 3491 * Permit top-level await in dead code branches ([#2853](https://github.com/evanw/esbuild/issues/2853)) 3492 3493 Adding top-level await to a file has a few consequences with esbuild: 3494 3495 1. It causes esbuild to assume that the input module format is ESM, since top-level await is only syntactically valid in ESM. That prevents you from using `module` and `exports` for exports and also enables strict mode, which disables certain syntax and changes how function hoisting works (among other things). 3496 2. This will cause esbuild to fail the build if either top-level await isn't supported by your language target (e.g. it's not supported in ES2021) or if top-level await isn't supported by the chosen output format (e.g. it's not supported with CommonJS). 3497 3. Doing this will prevent you from using `require()` on this file or on any file that imports this file (even indirectly), since the `require()` function doesn't return a promise and so can't represent top-level await. 3498 3499 This release relaxes these rules slightly: rules 2 and 3 will now no longer apply when esbuild has identified the code branch as dead code, such as when it's behind an `if (false)` check. This should make it possible to use esbuild to convert code into different output formats that only uses top-level await conditionally. This release does not relax rule 1. Top-level await will still cause esbuild to unconditionally consider the input module format to be ESM, even when the top-level `await` is in a dead code branch. This is necessary because whether the input format is ESM or not affects the whole file, not just the dead code branch. 3500 3501 * Fix entry points where the entire file name is the extension ([#2861](https://github.com/evanw/esbuild/issues/2861)) 3502 3503 Previously if you passed esbuild an entry point where the file extension is the entire file name, esbuild would use the parent directory name to derive the name of the output file. For example, if you passed esbuild a file `./src/.ts` then the output name would be `src.js`. This bug happened because esbuild first strips the file extension to get `./src/` and then joins the path with the working directory to get the absolute path (e.g. `join("/working/dir", "./src/")` gives `/working/dir/src`). However, the join operation also canonicalizes the path which strips the trailing `/`. Later esbuild uses the "base name" operation to extract the name of the output file. Since there is no trailing `/`, esbuild returns `"src"` as the base name instead of `""`, which causes esbuild to incorrectly include the directory name in the output file name. This release fixes this bug by deferring the stripping of the file extension until after all path manipulations have been completed. So now the file `./src/.ts` will generate an output file named `.js`. 3504 3505 * Support replacing property access expressions with inject 3506 3507 At a high level, this change means the `inject` feature can now replace all of the same kinds of names as the `define` feature. So `inject` is basically now a more powerful version of `define`, instead of previously only being able to do some of the things that `define` could do. 3508 3509 Soem background is necessary to understand this change if you aren't already familiar with the `inject` feature. The `inject` feature lets you replace references to global variable with a shim. It works like this: 3510 3511 1. Put the shim in its own file 3512 2. Export the shim as the name of the global variable you intend to replace 3513 3. Pass the file to esbuild using the `inject` feature 3514 3515 For example, if you inject the following file using `--inject:./injected.js`: 3516 3517 ```js 3518 // injected.js 3519 let processShim = { cwd: () => '/' } 3520 export { processShim as process } 3521 ``` 3522 3523 Then esbuild will replace all references to `process` with the `processShim` variable, which will cause `process.cwd()` to return `'/'`. This feature is sort of abusing the ESM export alias syntax to specify the mapping of global variables to shims. But esbuild works this way because using this syntax for that purpose is convenient and terse. 3524 3525 However, if you wanted to replace a property access expression, the process was more complicated and not as nice. You would have to: 3526 3527 1. Put the shim in its own file 3528 2. Export the shim as some random name 3529 3. Pass the file to esbuild using the `inject` feature 3530 4. Use esbuild's `define` feature to map the property access expression to the random name you made in step 2 3531 3532 For example, if you inject the following file using `--inject:./injected2.js --define:process.cwd=someRandomName`: 3533 3534 ```js 3535 // injected2.js 3536 let cwdShim = () => '/' 3537 export { cwdShim as someRandomName } 3538 ``` 3539 3540 Then esbuild will replace all references to `process.cwd` with the `cwdShim` variable, which will also cause `process.cwd()` to return `'/'` (but which this time will not mess with other references to `process`, which might be desirable). 3541 3542 With this release, using the inject feature to replace a property access expression is now as simple as using it to replace an identifier. You can now use JavaScript's ["arbitrary moduleĀ namespace identifierĀ names"](https://github.com/tc39/ecma262/pull/2154) feature to specify the property access expression directly using a string literal. For example, if you inject the following file using `--inject:./injected3.js`: 3543 3544 ```js 3545 // injected3.js 3546 let cwdShim = () => '/' 3547 export { cwdShim as 'process.cwd' } 3548 ``` 3549 3550 Then esbuild will now replace all references to `process.cwd` with the `cwdShim` variable, which will also cause `process.cwd()` to return `'/'` (but which will also not mess with other references to `process`). 3551 3552 In addition to inserting a shim for a global variable that doesn't exist, another use case is replacing references to static methods on global objects with cached versions to both minify them better and to make access to them potentially faster. For example: 3553 3554 ```js 3555 // Injected file 3556 let cachedMin = Math.min 3557 let cachedMax = Math.max 3558 export { 3559 cachedMin as 'Math.min', 3560 cachedMax as 'Math.max', 3561 } 3562 3563 // Original input 3564 function clampRGB(r, g, b) { 3565 return { 3566 r: Math.max(0, Math.min(1, r)), 3567 g: Math.max(0, Math.min(1, g)), 3568 b: Math.max(0, Math.min(1, b)), 3569 } 3570 } 3571 3572 // Old output (with --minify) 3573 function clampRGB(a,t,m){return{r:Math.max(0,Math.min(1,a)),g:Math.max(0,Math.min(1,t)),b:Math.max(0,Math.min(1,m))}} 3574 3575 // New output (with --minify) 3576 var a=Math.min,t=Math.max;function clampRGB(h,M,m){return{r:t(0,a(1,h)),g:t(0,a(1,M)),b:t(0,a(1,m))}} 3577 ``` 3578 3579 ## 0.17.3 3580 3581 * Fix incorrect CSS minification for certain rules ([#2838](https://github.com/evanw/esbuild/issues/2838)) 3582 3583 Certain rules such as `@media` could previously be minified incorrectly. Due to a typo in the duplicate rule checker, two known `@`-rules that share the same hash code were incorrectly considered to be equal. This problem was made worse by the rule hashing code considering two unknown declarations (such as CSS variables) to have the same hash code, which also isn't optimal from a performance perspective. Both of these issues have been fixed: 3584 3585 ```css 3586 /* Original input */ 3587 @media (prefers-color-scheme: dark) { body { --VAR-1: #000; } } 3588 @media (prefers-color-scheme: dark) { body { --VAR-2: #000; } } 3589 3590 /* Old output (with --minify) */ 3591 @media (prefers-color-scheme: dark){body{--VAR-2: #000}} 3592 3593 /* New output (with --minify) */ 3594 @media (prefers-color-scheme: dark){body{--VAR-1: #000}}@media (prefers-color-scheme: dark){body{--VAR-2: #000}} 3595 ``` 3596 3597 ## 0.17.2 3598 3599 * Add `onDispose` to the plugin API ([#2140](https://github.com/evanw/esbuild/issues/2140), [#2205](https://github.com/evanw/esbuild/issues/2205)) 3600 3601 If your plugin wants to perform some cleanup after it's no longer going to be used, you can now use the `onDispose` API to register a callback for cleanup-related tasks. For example, if a plugin starts a long-running child process then it may want to terminate that process when the plugin is discarded. Previously there was no way to do this. Here's an example: 3602 3603 ```js 3604 let examplePlugin = { 3605 name: 'example', 3606 setup(build) { 3607 build.onDispose(() => { 3608 console.log('This plugin is no longer used') 3609 }) 3610 }, 3611 } 3612 ``` 3613 3614 These `onDispose` callbacks will be called after every `build()` call regardless of whether the build failed or not as well as after the first `dispose()` call on a given build context. 3615 3616 ## 0.17.1 3617 3618 * Make it possible to cancel a build ([#2725](https://github.com/evanw/esbuild/issues/2725)) 3619 3620 The context object introduced in version 0.17.0 has a new `cancel()` method. You can use it to cancel a long-running build so that you can start a new one without needing to wait for the previous one to finish. When this happens, the previous build should always have at least one error and have no output files (i.e. it will be a failed build). 3621 3622 Using it might look something like this: 3623 3624 * JS: 3625 3626 ```js 3627 let ctx = await esbuild.context({ 3628 // ... 3629 }) 3630 3631 let rebuildWithTimeLimit = timeLimit => { 3632 let timeout = setTimeout(() => ctx.cancel(), timeLimit) 3633 return ctx.rebuild().finally(() => clearTimeout(timeout)) 3634 } 3635 3636 let build = await rebuildWithTimeLimit(500) 3637 ``` 3638 3639 * Go: 3640 3641 ```go 3642 ctx, err := api.Context(api.BuildOptions{ 3643 // ... 3644 }) 3645 if err != nil { 3646 return 3647 } 3648 3649 rebuildWithTimeLimit := func(timeLimit time.Duration) api.BuildResult { 3650 t := time.NewTimer(timeLimit) 3651 go func() { 3652 <-t.C 3653 ctx.Cancel() 3654 }() 3655 result := ctx.Rebuild() 3656 t.Stop() 3657 return result 3658 } 3659 3660 build := rebuildWithTimeLimit(500 * time.Millisecond) 3661 ``` 3662 3663 This API is a quick implementation and isn't maximally efficient, so the build may continue to do some work for a little bit before stopping. For example, I have added stop points between each top-level phase of the bundler and in the main module graph traversal loop, but I haven't added fine-grained stop points within the internals of the linker. How quickly esbuild stops can be improved in future releases. This means you'll want to wait for `cancel()` and/or the previous `rebuild()` to finish (i.e. await the returned promise in JavaScript) before starting a new build, otherwise `rebuild()` will give you the just-canceled build that still hasn't ended yet. Note that `onEnd` callbacks will still be run regardless of whether or not the build was canceled. 3664 3665 * Fix server-sent events without `servedir` ([#2827](https://github.com/evanw/esbuild/issues/2827)) 3666 3667 The server-sent events for live reload were incorrectly using `servedir` to calculate the path to modified output files. This means events couldn't be sent when `servedir` wasn't specified. This release uses the internal output directory (which is always present) instead of `servedir` (which might be omitted), so live reload should now work when `servedir` is not specified. 3668 3669 * Custom entry point output paths now work with the `copy` loader ([#2828](https://github.com/evanw/esbuild/issues/2828)) 3670 3671 Entry points can optionally provide custom output paths to change the path of the generated output file. For example, `esbuild foo=abc.js bar=xyz.js --outdir=out` generates the files `out/foo.js` and `out/bar.js`. However, this previously didn't work when using the `copy` loader due to an oversight. This bug has been fixed. For example, you can now do `esbuild foo=abc.html bar=xyz.html --outdir=out --loader:.html=copy` to generate the files `out/foo.html` and `out/bar.html`. 3672 3673 * The JS API can now take an array of objects ([#2828](https://github.com/evanw/esbuild/issues/2828)) 3674 3675 Previously it was not possible to specify two entry points with the same custom output path using the JS API, although it was possible to do this with the Go API and the CLI. This will not cause a collision if both entry points use different extensions (e.g. if one uses `.js` and the other uses `.css`). You can now pass the JS API an array of objects to work around this API limitation: 3676 3677 ```js 3678 // The previous API didn't let you specify duplicate output paths 3679 let result = await esbuild.build({ 3680 entryPoints: { 3681 // This object literal contains a duplicate key, so one is ignored 3682 'dist': 'foo.js', 3683 'dist': 'bar.css', 3684 }, 3685 }) 3686 3687 // You can now specify duplicate output paths as an array of objects 3688 let result = await esbuild.build({ 3689 entryPoints: [ 3690 { in: 'foo.js', out: 'dist' }, 3691 { in: 'bar.css', out: 'dist' }, 3692 ], 3693 }) 3694 ``` 3695 3696 ## 0.17.0 3697 3698 **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.16.0` or `~0.16.0`. See npm's documentation about [semver](https://docs.npmjs.com/cli/v6/using-npm/semver/) for more information. 3699 3700 At a high level, the breaking changes in this release fix some long-standing issues with the design of esbuild's incremental, watch, and serve APIs. This release also introduces some exciting new features such as live reloading. In detail: 3701 3702 * Move everything related to incremental builds to a new `context` API ([#1037](https://github.com/evanw/esbuild/issues/1037), [#1606](https://github.com/evanw/esbuild/issues/1606), [#2280](https://github.com/evanw/esbuild/issues/2280), [#2418](https://github.com/evanw/esbuild/issues/2418)) 3703 3704 This change removes the `incremental` and `watch` options as well as the `serve()` method, and introduces a new `context()` method. The context method takes the same arguments as the `build()` method but only validates its arguments and does not do an initial build. Instead, builds can be triggered using the `rebuild()`, `watch()`, and `serve()` methods on the returned context object. The new context API looks like this: 3705 3706 ```js 3707 // Create a context for incremental builds 3708 const context = await esbuild.context({ 3709 entryPoints: ['app.ts'], 3710 bundle: true, 3711 }) 3712 3713 // Manually do an incremental build 3714 const result = await context.rebuild() 3715 3716 // Enable watch mode 3717 await context.watch() 3718 3719 // Enable serve mode 3720 await context.serve() 3721 3722 // Dispose of the context 3723 context.dispose() 3724 ``` 3725 3726 The switch to the context API solves a major issue with the previous API which is that if the initial build fails, a promise is thrown in JavaScript which prevents you from accessing the returned result object. That prevented you from setting up long-running operations such as watch mode when the initial build contained errors. It also makes tearing down incremental builds simpler as there is now a single way to do it instead of three separate ways. 3727 3728 In addition, this release also makes some subtle changes to how incremental builds work. Previously every call to `rebuild()` started a new build. If you weren't careful, then builds could actually overlap. This doesn't cause any problems with esbuild itself, but could potentially cause problems with plugins (esbuild doesn't even give you a way to identify which overlapping build a given plugin callback is running on). Overlapping builds also arguably aren't useful, or at least aren't useful enough to justify the confusion and complexity that they bring. With this release, there is now only ever a single active build per context. Calling `rebuild()` before the previous rebuild has finished now "merges" with the existing rebuild instead of starting a new build. 3729 3730 * Allow using `watch` and `serve` together ([#805](https://github.com/evanw/esbuild/issues/805), [#1650](https://github.com/evanw/esbuild/issues/1650), [#2576](https://github.com/evanw/esbuild/issues/2576)) 3731 3732 Previously it was not possible to use watch mode and serve mode together. The rationale was that watch mode is one way of automatically rebuilding your project and serve mode is another (since serve mode automatically rebuilds on every request). However, people want to combine these two features to make "live reloading" where the browser automatically reloads the page when files are changed on the file system. 3733 3734 This release now allows you to use these two features together. You can only call the `watch()` and `serve()` APIs once each per context, but if you call them together on the same context then esbuild will automatically rebuild both when files on the file system are changed *and* when the server serves a request. 3735 3736 * Support "live reloading" through server-sent events ([#802](https://github.com/evanw/esbuild/issues/802)) 3737 3738 [Server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events) are a simple way to pass one-directional messages asynchronously from the server to the client. Serve mode now provides a `/esbuild` endpoint with an `change` event that triggers every time esbuild's output changes. So you can now implement simple "live reloading" (i.e. reloading the page when a file is edited and saved) like this: 3739 3740 ```js 3741 new EventSource('/esbuild').addEventListener('change', () => location.reload()) 3742 ``` 3743 3744 The event payload is a JSON object with the following shape: 3745 3746 ```ts 3747 interface ChangeEvent { 3748 added: string[] 3749 removed: string[] 3750 updated: string[] 3751 } 3752 ``` 3753 3754 This JSON should also enable more complex live reloading scenarios. For example, the following code hot-swaps changed CSS `<link>` tags in place without reloading the page (but still reloads when there are other types of changes): 3755 3756 ```js 3757 new EventSource('/esbuild').addEventListener('change', e => { 3758 const { added, removed, updated } = JSON.parse(e.data) 3759 if (!added.length && !removed.length && updated.length === 1) { 3760 for (const link of document.getElementsByTagName("link")) { 3761 const url = new URL(link.href) 3762 if (url.host === location.host && url.pathname === updated[0]) { 3763 const next = link.cloneNode() 3764 next.href = updated[0] + '?' + Math.random().toString(36).slice(2) 3765 next.onload = () => link.remove() 3766 link.parentNode.insertBefore(next, link.nextSibling) 3767 return 3768 } 3769 } 3770 } 3771 location.reload() 3772 }) 3773 ``` 3774 3775 Implementing live reloading like this has a few known caveats: 3776 3777 * These events only trigger when esbuild's output changes. They do not trigger when files unrelated to the build being watched are changed. If your HTML file references other files that esbuild doesn't know about and those files are changed, you can either manually reload the page or you can implement your own live reloading infrastructure instead of using esbuild's built-in behavior. 3778 3779 * The `EventSource` API is supposed to automatically reconnect for you. However, there's a bug in Firefox that breaks this if the server is ever temporarily unreachable: https://bugzilla.mozilla.org/show_bug.cgi?id=1809332. Workarounds are to use any other browser, to manually reload the page if this happens, or to write more complicated code that manually closes and re-creates the `EventSource` object if there is a connection error. I'm hopeful that this bug will be fixed. 3780 3781 * Browser vendors have decided to not implement HTTP/2 without TLS. This means that each `/esbuild` event source will take up one of your precious 6 simultaneous per-domain HTTP/1.1 connections. So if you open more than six HTTP tabs that use this live-reloading technique, you will be unable to use live reloading in some of those tabs (and other things will likely also break). The workaround is to enable HTTPS, which is now possible to do in esbuild itself (see below). 3782 3783 * Add built-in support for HTTPS ([#2169](https://github.com/evanw/esbuild/issues/2169)) 3784 3785 You can now tell esbuild's built-in development server to use HTTPS instead of HTTP. This is sometimes necessary because browser vendors have started making modern web features unavailable to HTTP websites. Previously you had to put a proxy in front of esbuild to enable HTTPS since esbuild's development server only supported HTTP. But with this release, you can now enable HTTPS with esbuild without an additional proxy. 3786 3787 To enable HTTPS with esbuild: 3788 3789 1. Generate a self-signed certificate. There are many ways to do this. Here's one way, assuming you have `openssl` installed: 3790 3791 ``` 3792 openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 9999 -nodes -subj /CN=127.0.0.1 3793 ``` 3794 3795 2. Add `--keyfile=key.pem` and `--certfile=cert.pem` to your esbuild development server command 3796 3. Click past the scary warning in your browser when you load your page 3797 3798 If you have more complex needs than this, you can still put a proxy in front of esbuild and use that for HTTPS instead. Note that if you see the message "Client sent an HTTP request to an HTTPS server" when you load your page, then you are using the incorrect protocol. Replace `http://` with `https://` in your browser's URL bar. 3799 3800 Keep in mind that esbuild's HTTPS support has nothing to do with security. The only reason esbuild now supports HTTPS is because browsers have made it impossible to do local development with certain modern web features without jumping through these extra hoops. *Please do not use esbuild's development server for anything that needs to be secure.* It's only intended for local development and no considerations have been made for production environments whatsoever. 3801 3802 * Better support copying `index.html` into the output directory ([#621](https://github.com/evanw/esbuild/issues/621), [#1771](https://github.com/evanw/esbuild/issues/1771)) 3803 3804 Right now esbuild only supports JavaScript and CSS as first-class content types. Previously this meant that if you were building a website with a HTML file, a JavaScript file, and a CSS file, you could use esbuild to build the JavaScript file and the CSS file into the output directory but not to copy the HTML file into the output directory. You needed a separate `cp` command for that. 3805 3806 Or so I thought. It turns out that the `copy` loader added in version 0.14.44 of esbuild is sufficient to have esbuild copy the HTML file into the output directory as well. You can add something like `index.html --loader:.html=copy` and esbuild will copy `index.html` into the output directory for you. The benefits of this are a) you don't need a separate `cp` command and b) the `index.html` file will automatically be re-copied when esbuild is in watch mode and the contents of `index.html` are edited. This also goes for other non-HTML file types that you might want to copy. 3807 3808 This pretty much already worked. The one thing that didn't work was that esbuild's built-in development server previously only supported implicitly loading `index.html` (e.g. loading `/about/index.html` when you visit `/about/`) when `index.html` existed on the file system. Previously esbuild didn't support implicitly loading `index.html` if it was a build result. That bug has been fixed with this release so it should now be practical to use the `copy` loader to do this. 3809 3810 * Fix `onEnd` not being called in serve mode ([#1384](https://github.com/evanw/esbuild/issues/1384)) 3811 3812 Previous releases had a bug where plugin `onEnd` callbacks weren't called when using the top-level `serve()` API. This API no longer exists and the internals have been reimplemented such that `onEnd` callbacks should now always be called at the end of every build. 3813 3814 * Incremental builds now write out build results differently ([#2104](https://github.com/evanw/esbuild/issues/2104)) 3815 3816 Previously build results were always written out after every build. However, this could cause the output directory to fill up with files from old builds if code splitting was enabled, since the file names for code splitting chunks contain content hashes and old files were not deleted. 3817 3818 With this release, incremental builds in esbuild will now delete old output files from previous builds that are no longer relevant. Subsequent incremental builds will also no longer overwrite output files whose contents haven't changed since the previous incremental build. 3819 3820 * The `onRebuild` watch mode callback was removed ([#980](https://github.com/evanw/esbuild/issues/980), [#2499](https://github.com/evanw/esbuild/issues/2499)) 3821 3822 Previously watch mode accepted an `onRebuild` callback which was called whenever watch mode rebuilt something. This was not great in practice because if you are running code after a build, you likely want that code to run after every build, not just after the second and subsequent builds. This release removes option to provide an `onRebuild` callback. You can create a plugin with an `onEnd` callback instead. The `onEnd` plugin API already exists, and is a way to run some code after every build. 3823 3824 * You can now return errors from `onEnd` ([#2625](https://github.com/evanw/esbuild/issues/2625)) 3825 3826 It's now possible to add additional build errors and/or warnings to the current build from within your `onEnd` callback by returning them in an array. This is identical to how the `onStart` callback already works. The evaluation of `onEnd` callbacks have been moved around a bit internally to make this possible. 3827 3828 Note that the build will only fail (i.e. reject the promise) if the additional errors are returned from `onEnd`. Adding additional errors to the result object that's passed to `onEnd` won't affect esbuild's behavior at all. 3829 3830 * Print URLs and ports from the Go and JS APIs ([#2393](https://github.com/evanw/esbuild/issues/2393)) 3831 3832 Previously esbuild's CLI printed out something like this when serve mode is active: 3833 3834 ``` 3835 > Local: http://127.0.0.1:8000/ 3836 > Network: http://192.168.0.1:8000/ 3837 ``` 3838 3839 The CLI still does this, but now the JS and Go serve mode APIs will do this too. This only happens when the log level is set to `verbose`, `debug`, or `info` but not when it's set to `warning`, `error`, or `silent`. 3840 3841 ### Upgrade guide for existing code: 3842 3843 * Rebuild (a.k.a. incremental build): 3844 3845 Before: 3846 3847 ```js 3848 const result = await esbuild.build({ ...buildOptions, incremental: true }); 3849 builds.push(result); 3850 for (let i = 0; i < 4; i++) builds.push(await result.rebuild()); 3851 await result.rebuild.dispose(); // To free resources 3852 ``` 3853 3854 After: 3855 3856 ```js 3857 const ctx = await esbuild.context(buildOptions); 3858 for (let i = 0; i < 5; i++) builds.push(await ctx.rebuild()); 3859 await ctx.dispose(); // To free resources 3860 ``` 3861 3862 Previously the first build was done differently than subsequent builds. Now both the first build and subsequent builds are done using the same API. 3863 3864 * Serve: 3865 3866 Before: 3867 3868 ```js 3869 const serveResult = await esbuild.serve(serveOptions, buildOptions); 3870 ... 3871 serveResult.stop(); await serveResult.wait; // To free resources 3872 ``` 3873 3874 After: 3875 3876 ```js 3877 const ctx = await esbuild.context(buildOptions); 3878 const serveResult = await ctx.serve(serveOptions); 3879 ... 3880 await ctx.dispose(); // To free resources 3881 ``` 3882 3883 * Watch: 3884 3885 Before: 3886 3887 ```js 3888 const result = await esbuild.build({ ...buildOptions, watch: true }); 3889 ... 3890 result.stop(); // To free resources 3891 ``` 3892 3893 After: 3894 3895 ```js 3896 const ctx = await esbuild.context(buildOptions); 3897 await ctx.watch(); 3898 ... 3899 await ctx.dispose(); // To free resources 3900 ``` 3901 3902 * Watch with `onRebuild`: 3903 3904 Before: 3905 3906 ```js 3907 const onRebuild = (error, result) => { 3908 if (error) console.log('subsequent build:', error); 3909 else console.log('subsequent build:', result); 3910 }; 3911 try { 3912 const result = await esbuild.build({ ...buildOptions, watch: { onRebuild } }); 3913 console.log('first build:', result); 3914 ... 3915 result.stop(); // To free resources 3916 } catch (error) { 3917 console.log('first build:', error); 3918 } 3919 ``` 3920 3921 After: 3922 3923 ```js 3924 const plugins = [{ 3925 name: 'my-plugin', 3926 setup(build) { 3927 let count = 0; 3928 build.onEnd(result => { 3929 if (count++ === 0) console.log('first build:', result); 3930 else console.log('subsequent build:', result); 3931 }); 3932 }, 3933 }]; 3934 const ctx = await esbuild.context({ ...buildOptions, plugins }); 3935 await ctx.watch(); 3936 ... 3937 await ctx.dispose(); // To free resources 3938 ``` 3939 3940 The `onRebuild` function has now been removed. The replacement is to make a plugin with an `onEnd` callback. 3941 3942 Previously `onRebuild` did not fire for the first build (only for subsequent builds). This was usually problematic, so using `onEnd` instead of `onRebuild` is likely less error-prone. But if you need to emulate the old behavior of `onRebuild` that ignores the first build, then you'll need to manually count and ignore the first build in your plugin (as demonstrated above). 3943 3944 Notice how all of these API calls are now done off the new context object. You should now be able to use all three kinds of incremental builds (`rebuild`, `serve`, and `watch`) together on the same context object. Also notice how calling `dispose` on the context is now the common way to discard the context and free resources in all of these situations. 3945 3946 ## 0.16.17 3947 3948 * Fix additional comment-related regressions ([#2814](https://github.com/evanw/esbuild/issues/2814)) 3949 3950 This release fixes more edge cases where the new comment preservation behavior that was added in 0.16.14 could introduce syntax errors. Specifically: 3951 3952 ```js 3953 x = () => (/* comment */ {}) 3954 for ((/* comment */ let).x of y) ; 3955 function *f() { yield (/* comment */class {}) } 3956 ``` 3957 3958 These cases caused esbuild to generate code with a syntax error in version 0.16.14 or above. These bugs have now been fixed. 3959 3960 ## 0.16.16 3961 3962 * Fix a regression caused by comment preservation ([#2805](https://github.com/evanw/esbuild/issues/2805)) 3963 3964 The new comment preservation behavior that was added in 0.16.14 introduced a regression where comments in certain locations could cause esbuild to omit certain necessary parentheses in the output. The outermost parentheses were incorrectly removed for the following syntax forms, which then introduced syntax errors: 3965 3966 ```js 3967 (/* comment */ { x: 0 }).x; 3968 (/* comment */ function () { })(); 3969 (/* comment */ class { }).prototype; 3970 ``` 3971 3972 This regression has been fixed. 3973 3974 ## 0.16.15 3975 3976 * Add `format` to input files in the JSON metafile data 3977 3978 When `--metafile` is enabled, input files may now have an additional `format` field that indicates the export format used by this file. When present, the value will either be `cjs` for CommonJS-style exports or `esm` for ESM-style exports. This can be useful in bundle analysis. 3979 3980 For example, esbuild's new [Bundle Size Analyzer](https://esbuild.github.io/analyze/) now uses this information to visualize whether ESM or CommonJS was used for each directory and file of source code (click on the CJS/ESM bar at the top). 3981 3982 This information is helpful when trying to reduce the size of your bundle. Using the ESM variant of a dependency instead of the CommonJS variant always results in a faster and smaller bundle because it omits CommonJS wrappers, and also may result in better tree-shaking as it allows esbuild to perform tree-shaking at the statement level instead of the module level. 3983 3984 * Fix a bundling edge case with dynamic import ([#2793](https://github.com/evanw/esbuild/issues/2793)) 3985 3986 This release fixes a bug where esbuild's bundler could produce incorrect output. The problematic edge case involves the entry point importing itself using a dynamic `import()` expression in an imported file, like this: 3987 3988 ```js 3989 // src/a.js 3990 export const A = 42; 3991 3992 // src/b.js 3993 export const B = async () => (await import(".")).A 3994 3995 // src/index.js 3996 export * from "./a" 3997 export * from "./b" 3998 ``` 3999 4000 * Remove new type syntax from type declarations in the `esbuild` package ([#2798](https://github.com/evanw/esbuild/issues/2798)) 4001 4002 Previously you needed to use TypeScript 4.3 or newer when using the `esbuild` package from TypeScript code due to the use of a getter in an interface in `node_modules/esbuild/lib/main.d.ts`. This release removes this newer syntax to allow people with versions of TypeScript as far back as TypeScript 3.5 to use this latest version of the `esbuild` package. Here is change that was made to esbuild's type declarations: 4003 4004 ```diff 4005 export interface OutputFile { 4006 /** "text" as bytes */ 4007 contents: Uint8Array; 4008 /** "contents" as text (changes automatically with "contents") */ 4009 - get text(): string; 4010 + readonly text: string; 4011 } 4012 ``` 4013 4014 ## 0.16.14 4015 4016 * Preserve some comments in expressions ([#2721](https://github.com/evanw/esbuild/issues/2721)) 4017 4018 Various tools give semantic meaning to comments embedded inside of expressions. For example, Webpack and Vite have special "magic comments" that can be used to affect code splitting behavior: 4019 4020 ```js 4021 import(/* webpackChunkName: "foo" */ '../foo'); 4022 import(/* @vite-ignore */ dynamicVar); 4023 new Worker(/* webpackChunkName: "bar" */ new URL("../bar.ts", import.meta.url)); 4024 new Worker(new URL('./path', import.meta.url), /* @vite-ignore */ dynamicOptions); 4025 ``` 4026 4027 Since esbuild can be used as a preprocessor for these tools (e.g. to strip TypeScript types), it can be problematic if esbuild doesn't do additional work to try to retain these comments. Previously esbuild special-cased Webpack comments in these specific locations in the AST. But Vite would now like to use similar comments, and likely other tools as well. 4028 4029 So with this release, esbuild now will attempt to preserve some comments inside of expressions in more situations than before. This behavior is mainly intended to preserve these special "magic comments" that are meant for other tools to consume, although esbuild will no longer only preserve Webpack-specific comments so it should now be tool-agnostic. There is no guarantee that all such comments will be preserved (especially when `--minify-syntax` is enabled). So this change does *not* mean that esbuild is now usable as a code formatter. In particular comment preservation is more likely to happen with leading comments than with trailing comments. You should put comments that you want to be preserved *before* the relevant expression instead of after it. Also note that this change does not retain any more statement-level comments than before (i.e. comments not embedded inside of expressions). Comment preservation is not enabled when `--minify-whitespace` is enabled (which is automatically enabled when you use `--minify`). 4030 4031 ## 0.16.13 4032 4033 * Publish a new bundle visualization tool 4034 4035 While esbuild provides bundle metadata via the `--metafile` flag, previously esbuild left analysis of it completely up to third-party tools (well, outside of the rudimentary `--analyze` flag). However, the esbuild website now has a built-in bundle visualization tool: 4036 4037 * https://esbuild.github.io/analyze/ 4038 4039 You can pass `--metafile` to esbuild to output bundle metadata, then upload that JSON file to this tool to visualize your bundle. This is helpful for answering questions such as: 4040 4041 * Which packages are included in my bundle? 4042 * How did a specific file get included? 4043 * How small did a specific file compress to? 4044 * Was a specific file tree-shaken or not? 4045 4046 I'm publishing this tool because I think esbuild should provide *some* answer to "how do I visualize my bundle" without requiring people to reach for third-party tools. At the moment the tool offers two types of visualizations: a radial "sunburst chart" and a linear "flame chart". They serve slightly different but overlapping use cases (e.g. the sunburst chart is more keyboard-accessible while the flame chart is easier with the mouse). This tool may continue to evolve over time. 4047 4048 * Fix `--metafile` and `--mangle-cache` with `--watch` ([#1357](https://github.com/evanw/esbuild/issues/1357)) 4049 4050 The CLI calls the Go API and then also writes out the metafile and/or mangle cache JSON files if those features are enabled. This extra step is necessary because these files are returned by the Go API as in-memory strings. However, this extra step accidentally didn't happen for all builds after the initial build when watch mode was enabled. This behavior used to work but it was broken in version 0.14.18 by the introduction of the mangle cache feature. This release fixes the combination of these features, so the metafile and mangle cache features should now work with watch mode. This behavior was only broken for the CLI, not for the JS or Go APIs. 4051 4052 * Add an `original` field to the metafile 4053 4054 The metadata file JSON now has an additional field: each import in an input file now contains the pre-resolved path in the `original` field in addition to the post-resolved path in the `path` field. This means it's now possible to run certain additional analysis over your bundle. For example, you should be able to use this to detect when the same package subpath is represented multiple times in the bundle, either because multiple versions of a package were bundled or because a package is experiencing the [dual-package hazard](https://nodejs.org/api/packages.html#dual-package-hazard).