evanw/esbuild
### [`v0.14.6`](https://togithub.com/evanw/esbuild/blob/HEAD/CHANGELOG.md#0146)
[Compare Source](https://togithub.com/evanw/esbuild/compare/v0.14.5...v0.14.6)
- Fix a minifier bug with BigInt literals
Previously expression simplification optimizations in the minifier incorrectly assumed that numeric operators always return numbers. This used to be true but has no longer been true since the introduction of BigInt literals in ES2020. Now numeric operators can return either a number or a BigInt depending on the arguments. This oversight could potentially have resulted in behavior changes. For example, this code printed `false` before being minified and `true` after being minified because esbuild shortened `===` to `==` under the false assumption that both operands were numbers:
```js
var x = 0;
console.log((x ? 2 : -1n) === -1);
```
The type checking logic has been rewritten to take into account BigInt literals in this release, so this incorrect simplification is no longer applied.
- Enable removal of certain unused template literals ([#1853](https://togithub.com/evanw/esbuild/issues/1853))
This release contains improvements to the minification of unused template literals containing primitive values:
```js
// Original code
`${1}${2}${3}`;
`${x ? 1 : 2}${y}`;
// Old output (with --minify)
""+1+2+3,""+(x?1:2)+y;
// New output (with --minify)
x,`${y}`;
```
This can arise when the template literals are nested inside of another function call that was determined to be unnecessary such as an unused call to a function marked with the `/* @__PURE__ */` pragma.
This release also fixes a bug with this transformation where minifying the unused expression `` `foo ${bar}` `` into `"" + bar` changed the meaning of the expression. Template string interpolation always calls `toString` while string addition may call `valueOf` instead. This unused expression is now minified to `` `${bar}` ``, which is slightly longer but which avoids the behavior change.
- Allow `keyof`/`readonly`/`infer` in TypeScript index signatures ([#1859](https://togithub.com/evanw/esbuild/pull/1859))
This release fixes a bug that prevented these keywords from being used as names in index signatures. The following TypeScript code was previously rejected, but is now accepted:
```ts
interface Foo {
[keyof: string]: number
}
```
This fix was contributed by [@magic-akari](https://togithub.com/magic-akari).
- Avoid warning about `import.meta` if it's replaced ([#1868](https://togithub.com/evanw/esbuild/issues/1868))
It's possible to replace the `import.meta` expression using the `--define:` feature. Previously doing that still warned that the `import.meta` syntax was not supported when targeting ES5. With this release, there will no longer be a warning in this case.
### [`v0.14.5`](https://togithub.com/evanw/esbuild/blob/HEAD/CHANGELOG.md#0145)
[Compare Source](https://togithub.com/evanw/esbuild/compare/v0.14.4...v0.14.5)
- Fix an issue with the publishing script
This release fixes a missing dependency issue in the publishing script where it was previously possible for the published binary executable to have an incorrect version number.
### [`v0.14.4`](https://togithub.com/evanw/esbuild/blob/HEAD/CHANGELOG.md#0144)
[Compare Source](https://togithub.com/evanw/esbuild/compare/v0.14.3...v0.14.4)
- Adjust esbuild's handling of `default` exports and the `__esModule` marker ([#532](https://togithub.com/evanw/esbuild/issues/532), [#1591](https://togithub.com/evanw/esbuild/issues/1591), [#1719](https://togithub.com/evanw/esbuild/issues/1719))
This change requires some background for context. Here's the history to the best of my understanding:
When the ECMAScript module `import`/`export` syntax was being developed, the CommonJS module format (used in Node.js) was already widely in use. Because of this the export name called `default` was given special a syntax. Instead of writing `import { default as foo } from 'bar'` you can just write `import foo from 'bar'`. The idea was that when ECMAScript modules (a.k.a. ES modules) were introduced, you could import existing CommonJS modules using the new import syntax for compatibility. Since CommonJS module exports are dynamic while ES module exports are static, it's not generally possible to determine a CommonJS module's export names at module instantiation time since the code hasn't been evaluated yet. So the value of `module.exports` is just exported as the `default` export and the special `default` import syntax gives you easy access to `module.exports` (i.e. `const foo = require('bar')` is the same as `import foo from 'bar'`).
However, it took a while for ES module syntax to be supported natively by JavaScript runtimes, and people still wanted to start using ES module syntax in the meantime. The [Babel](https://babeljs.io/) JavaScript compiler let you do this. You could transform each ES module file into a CommonJS module file that behaved the same. However, this transformation has a problem: emulating the `import` syntax accurately as described above means that `export default 0` and `import foo from 'bar'` will no longer line up when transformed to CommonJS. The code `export default 0` turns into `module.exports.default = 0` and the code `import foo from 'bar'` turns into `const foo = require('bar')`, meaning `foo` is `0` before the transformation but `foo` is `{ default: 0 }` after the transformation.
To fix this, Babel sets the property `__esModule` to true as a signal to itself when it converts an ES module to a CommonJS module. Then, when importing a `default` export, it can know to use the value of `module.exports.default` instead of `module.exports` to make sure the behavior of the CommonJS modules correctly matches the behavior of the original ES modules. This fix has been widely adopted across the ecosystem and has made it into other tools such as TypeScript and even esbuild.
However, when Node.js finally released their ES module implementation, they went with the original implementation where the `default` export is always `module.exports`, which broke compatibility with the existing ecosystem of ES modules that had been cross-compiled into CommonJS modules by Babel. You now have to either add or remove an additional `.default` property depending on whether your code needs to run in a Node environment or in a Babel environment, which created an interoperability headache. In addition, JavaScript tools such as esbuild now need to guess whether you want Node-style or Babel-style `default` imports. There's no way for a tool to know with certainty which one a given file is expecting and if your tool guesses wrong, your code will break.
This release changes esbuild's heuristics around `default` exports and the `__esModule` marker to attempt to improve compatibility with Webpack and Node, which is what most packages are tuned for. The behavior changes are as follows:
Old behavior:
- If an `import` statement is used to load a CommonJS file and a) `module.exports` is an object, b) `module.exports.__esModule` is truthy, and c) the property `default` exists in `module.exports`, then esbuild would set the `default` export to `module.exports.default` (like Babel). Otherwise the `default` export was set to `module.exports` (like Node).
- If a `require` call is used to load an ES module file, the returned module namespace object had the `__esModule` property set to true. This behaved as if the ES module had been converted to CommonJS via a Babel-compatible transformation.
- The `__esModule` marker could inconsistently appear on module namespace objects (i.e. `import * as`) when writing pure ESM code. Specifically, if a module namespace object was materialized then the `__esModule` marker was present, but if it was optimized away then the `__esModule` marker was absent.
- It was not allowed to create an ES module export named `__esModule`. This avoided generating code that might break due to the inconsistency mentioned above, and also avoided issues with duplicate definitions of `__esModule`.
New behavior:
- If an `import` statement is used to load a CommonJS file and a) `module.exports` is an object, b) `module.exports.__esModule` is truthy, and c) the file name does not end in either `.mjs` or `.mts` and the `package.json` file does not contain `"type": "module"`, then esbuild will set the `default` export to `module.exports.default` (like Babel). Otherwise the `default` export is set to `module.exports` (like Node).
Note that this means the `default` export may now be undefined in situations where it previously wasn't undefined. This matches Webpack's behavior so it should hopefully be more compatible.
Also note that this means import behavior now depends on the file extension and on the contents of `package.json`. This also matches Webpack's behavior to hopefully improve compatibility.
- If a `require` call is used to load an ES module file, the returned module namespace object has the `__esModule` property set to `true`. This behaves as if the ES module had been converted to CommonJS via a Babel-compatible transformation.
- If an `import` statement or `import()` expression is used to load an ES module, the `__esModule` marker should now never be present on the module namespace object. This frees up the `__esModule` export name for use with ES modules.
- It's now allowed to use `__esModule` as a normal export name in an ES module. This property will be accessible to other ES modules but will not be accessible to code that loads the ES module using `require`, where they will observe the property set to `true` instead.
### [`v0.14.3`](https://togithub.com/evanw/esbuild/blob/HEAD/CHANGELOG.md#0143)
[Compare Source](https://togithub.com/evanw/esbuild/compare/v0.14.2...v0.14.3)
- Pass the current esbuild instance to JS plugins ([#1790](https://togithub.com/evanw/esbuild/issues/1790))
Previously JS plugins that wanted to run esbuild had to `require('esbuild')` to get the esbuild object. However, that could potentially result in a different version of esbuild. This is also more complicated to do outside of node (such as within a browser). With this release, the current esbuild instance is now passed to JS plugins as the `esbuild` property:
```js
let examplePlugin = {
name: 'example',
setup(build) {
console.log(build.esbuild.version)
console.log(build.esbuild.transformSync('1+2'))
},
}
```
- Disable `calc()` transform for results with non-finite numbers ([#1839](https://togithub.com/evanw/esbuild/issues/1839))
This release disables minification of `calc()` expressions when the result contains `NaN`, `-Infinity`, or `Infinity`. These numbers are valid inside of `calc()` expressions but not outside of them, so the `calc()` expression must be preserved in these cases.
- Move `"use strict"` before injected shim imports ([#1837](https://togithub.com/evanw/esbuild/issues/1837))
If a CommonJS file contains a `"use strict"` directive, it could potentially be unintentionally disabled by esbuild when using the "inject" feature when bundling is enabled. This is because the inject feature was inserting a call to the initializer for the injected file before the `"use strict"` directive. In JavaScript, directives do not apply if they come after a non-directive statement. This release fixes the problem by moving the `"use strict"` directive before the initializer for the injected file so it isn't accidentally disabled.
- Pass the ignored path query/hash suffix to `onLoad` plugins ([#1827](https://togithub.com/evanw/esbuild/issues/1827))
The built-in `onResolve` handler that comes with esbuild can strip the query/hash suffix off of a path during path resolution. For example, `url("fonts/icons.eot?#iefix")` can be resolved to the file `fonts/icons.eot`. For context, IE8 has a bug where it considers the font face URL to extend to the last `)` instead of the first `)`. In the example below, IE8 thinks the URL for the font is `Example.eot?#iefix') format('eot'), url('Example.ttf') format('truetype` so by adding `?#iefix`, IE8 thinks the URL has a path of `Example.eot` and a query string of `?#iefix') format('eot...` and can load the font file:
```css
@font-face {
font-family: 'Example';
src: url('Example.eot?#iefix') format('eot'), url('Example.ttf') format('truetype');
}
```
However, the suffix is not currently passed to esbuild and plugins may want to use this suffix for something. Previously plugins had to add their own `onResolve` handler if they wanted to use the query suffix. With this release, the suffix can now be returned by plugins from `onResolve` and is now passed to plugins in `onLoad`:
```js
let examplePlugin = {
name: 'example',
setup(build) {
build.onResolve({ filter: /.*/ }, args => {
return { path: args.path, suffix: '?#iefix' }
})
build.onLoad({ filter: /.*/ }, args => {
console.log({ path: args.path, suffix: args.suffix })
})
},
}
```
The suffix is deliberately not included in the path that's provided to plugins because most plugins won't know to handle this strange edge case and would likely break. Keeping the suffix out of the path means that plugins can opt-in to handling this edge case if they want to, and plugins that aren't aware of this edge case will likely still do something reasonable.
Configuration
📅 Schedule: At any time (no schedule defined).
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
[ ] If you want to rebase/retry this PR, click this checkbox.
This PR contains the following updates:
0.14.2
->0.14.6
Release Notes
evanw/esbuild
### [`v0.14.6`](https://togithub.com/evanw/esbuild/blob/HEAD/CHANGELOG.md#0146) [Compare Source](https://togithub.com/evanw/esbuild/compare/v0.14.5...v0.14.6) - Fix a minifier bug with BigInt literals Previously expression simplification optimizations in the minifier incorrectly assumed that numeric operators always return numbers. This used to be true but has no longer been true since the introduction of BigInt literals in ES2020. Now numeric operators can return either a number or a BigInt depending on the arguments. This oversight could potentially have resulted in behavior changes. For example, this code printed `false` before being minified and `true` after being minified because esbuild shortened `===` to `==` under the false assumption that both operands were numbers: ```js var x = 0; console.log((x ? 2 : -1n) === -1); ``` The type checking logic has been rewritten to take into account BigInt literals in this release, so this incorrect simplification is no longer applied. - Enable removal of certain unused template literals ([#1853](https://togithub.com/evanw/esbuild/issues/1853)) This release contains improvements to the minification of unused template literals containing primitive values: ```js // Original code `${1}${2}${3}`; `${x ? 1 : 2}${y}`; // Old output (with --minify) ""+1+2+3,""+(x?1:2)+y; // New output (with --minify) x,`${y}`; ``` This can arise when the template literals are nested inside of another function call that was determined to be unnecessary such as an unused call to a function marked with the `/* @__PURE__ */` pragma. This release also fixes a bug with this transformation where minifying the unused expression `` `foo ${bar}` `` into `"" + bar` changed the meaning of the expression. Template string interpolation always calls `toString` while string addition may call `valueOf` instead. This unused expression is now minified to `` `${bar}` ``, which is slightly longer but which avoids the behavior change. - Allow `keyof`/`readonly`/`infer` in TypeScript index signatures ([#1859](https://togithub.com/evanw/esbuild/pull/1859)) This release fixes a bug that prevented these keywords from being used as names in index signatures. The following TypeScript code was previously rejected, but is now accepted: ```ts interface Foo { [keyof: string]: number } ``` This fix was contributed by [@magic-akari](https://togithub.com/magic-akari). - Avoid warning about `import.meta` if it's replaced ([#1868](https://togithub.com/evanw/esbuild/issues/1868)) It's possible to replace the `import.meta` expression using the `--define:` feature. Previously doing that still warned that the `import.meta` syntax was not supported when targeting ES5. With this release, there will no longer be a warning in this case. ### [`v0.14.5`](https://togithub.com/evanw/esbuild/blob/HEAD/CHANGELOG.md#0145) [Compare Source](https://togithub.com/evanw/esbuild/compare/v0.14.4...v0.14.5) - Fix an issue with the publishing script This release fixes a missing dependency issue in the publishing script where it was previously possible for the published binary executable to have an incorrect version number. ### [`v0.14.4`](https://togithub.com/evanw/esbuild/blob/HEAD/CHANGELOG.md#0144) [Compare Source](https://togithub.com/evanw/esbuild/compare/v0.14.3...v0.14.4) - Adjust esbuild's handling of `default` exports and the `__esModule` marker ([#532](https://togithub.com/evanw/esbuild/issues/532), [#1591](https://togithub.com/evanw/esbuild/issues/1591), [#1719](https://togithub.com/evanw/esbuild/issues/1719)) This change requires some background for context. Here's the history to the best of my understanding: When the ECMAScript module `import`/`export` syntax was being developed, the CommonJS module format (used in Node.js) was already widely in use. Because of this the export name called `default` was given special a syntax. Instead of writing `import { default as foo } from 'bar'` you can just write `import foo from 'bar'`. The idea was that when ECMAScript modules (a.k.a. ES modules) were introduced, you could import existing CommonJS modules using the new import syntax for compatibility. Since CommonJS module exports are dynamic while ES module exports are static, it's not generally possible to determine a CommonJS module's export names at module instantiation time since the code hasn't been evaluated yet. So the value of `module.exports` is just exported as the `default` export and the special `default` import syntax gives you easy access to `module.exports` (i.e. `const foo = require('bar')` is the same as `import foo from 'bar'`). However, it took a while for ES module syntax to be supported natively by JavaScript runtimes, and people still wanted to start using ES module syntax in the meantime. The [Babel](https://babeljs.io/) JavaScript compiler let you do this. You could transform each ES module file into a CommonJS module file that behaved the same. However, this transformation has a problem: emulating the `import` syntax accurately as described above means that `export default 0` and `import foo from 'bar'` will no longer line up when transformed to CommonJS. The code `export default 0` turns into `module.exports.default = 0` and the code `import foo from 'bar'` turns into `const foo = require('bar')`, meaning `foo` is `0` before the transformation but `foo` is `{ default: 0 }` after the transformation. To fix this, Babel sets the property `__esModule` to true as a signal to itself when it converts an ES module to a CommonJS module. Then, when importing a `default` export, it can know to use the value of `module.exports.default` instead of `module.exports` to make sure the behavior of the CommonJS modules correctly matches the behavior of the original ES modules. This fix has been widely adopted across the ecosystem and has made it into other tools such as TypeScript and even esbuild. However, when Node.js finally released their ES module implementation, they went with the original implementation where the `default` export is always `module.exports`, which broke compatibility with the existing ecosystem of ES modules that had been cross-compiled into CommonJS modules by Babel. You now have to either add or remove an additional `.default` property depending on whether your code needs to run in a Node environment or in a Babel environment, which created an interoperability headache. In addition, JavaScript tools such as esbuild now need to guess whether you want Node-style or Babel-style `default` imports. There's no way for a tool to know with certainty which one a given file is expecting and if your tool guesses wrong, your code will break. This release changes esbuild's heuristics around `default` exports and the `__esModule` marker to attempt to improve compatibility with Webpack and Node, which is what most packages are tuned for. The behavior changes are as follows: Old behavior: - If an `import` statement is used to load a CommonJS file and a) `module.exports` is an object, b) `module.exports.__esModule` is truthy, and c) the property `default` exists in `module.exports`, then esbuild would set the `default` export to `module.exports.default` (like Babel). Otherwise the `default` export was set to `module.exports` (like Node). - If a `require` call is used to load an ES module file, the returned module namespace object had the `__esModule` property set to true. This behaved as if the ES module had been converted to CommonJS via a Babel-compatible transformation. - The `__esModule` marker could inconsistently appear on module namespace objects (i.e. `import * as`) when writing pure ESM code. Specifically, if a module namespace object was materialized then the `__esModule` marker was present, but if it was optimized away then the `__esModule` marker was absent. - It was not allowed to create an ES module export named `__esModule`. This avoided generating code that might break due to the inconsistency mentioned above, and also avoided issues with duplicate definitions of `__esModule`. New behavior: - If an `import` statement is used to load a CommonJS file and a) `module.exports` is an object, b) `module.exports.__esModule` is truthy, and c) the file name does not end in either `.mjs` or `.mts` and the `package.json` file does not contain `"type": "module"`, then esbuild will set the `default` export to `module.exports.default` (like Babel). Otherwise the `default` export is set to `module.exports` (like Node). Note that this means the `default` export may now be undefined in situations where it previously wasn't undefined. This matches Webpack's behavior so it should hopefully be more compatible. Also note that this means import behavior now depends on the file extension and on the contents of `package.json`. This also matches Webpack's behavior to hopefully improve compatibility. - If a `require` call is used to load an ES module file, the returned module namespace object has the `__esModule` property set to `true`. This behaves as if the ES module had been converted to CommonJS via a Babel-compatible transformation. - If an `import` statement or `import()` expression is used to load an ES module, the `__esModule` marker should now never be present on the module namespace object. This frees up the `__esModule` export name for use with ES modules. - It's now allowed to use `__esModule` as a normal export name in an ES module. This property will be accessible to other ES modules but will not be accessible to code that loads the ES module using `require`, where they will observe the property set to `true` instead. ### [`v0.14.3`](https://togithub.com/evanw/esbuild/blob/HEAD/CHANGELOG.md#0143) [Compare Source](https://togithub.com/evanw/esbuild/compare/v0.14.2...v0.14.3) - Pass the current esbuild instance to JS plugins ([#1790](https://togithub.com/evanw/esbuild/issues/1790)) Previously JS plugins that wanted to run esbuild had to `require('esbuild')` to get the esbuild object. However, that could potentially result in a different version of esbuild. This is also more complicated to do outside of node (such as within a browser). With this release, the current esbuild instance is now passed to JS plugins as the `esbuild` property: ```js let examplePlugin = { name: 'example', setup(build) { console.log(build.esbuild.version) console.log(build.esbuild.transformSync('1+2')) }, } ``` - Disable `calc()` transform for results with non-finite numbers ([#1839](https://togithub.com/evanw/esbuild/issues/1839)) This release disables minification of `calc()` expressions when the result contains `NaN`, `-Infinity`, or `Infinity`. These numbers are valid inside of `calc()` expressions but not outside of them, so the `calc()` expression must be preserved in these cases. - Move `"use strict"` before injected shim imports ([#1837](https://togithub.com/evanw/esbuild/issues/1837)) If a CommonJS file contains a `"use strict"` directive, it could potentially be unintentionally disabled by esbuild when using the "inject" feature when bundling is enabled. This is because the inject feature was inserting a call to the initializer for the injected file before the `"use strict"` directive. In JavaScript, directives do not apply if they come after a non-directive statement. This release fixes the problem by moving the `"use strict"` directive before the initializer for the injected file so it isn't accidentally disabled. - Pass the ignored path query/hash suffix to `onLoad` plugins ([#1827](https://togithub.com/evanw/esbuild/issues/1827)) The built-in `onResolve` handler that comes with esbuild can strip the query/hash suffix off of a path during path resolution. For example, `url("fonts/icons.eot?#iefix")` can be resolved to the file `fonts/icons.eot`. For context, IE8 has a bug where it considers the font face URL to extend to the last `)` instead of the first `)`. In the example below, IE8 thinks the URL for the font is `Example.eot?#iefix') format('eot'), url('Example.ttf') format('truetype` so by adding `?#iefix`, IE8 thinks the URL has a path of `Example.eot` and a query string of `?#iefix') format('eot...` and can load the font file: ```css @font-face { font-family: 'Example'; src: url('Example.eot?#iefix') format('eot'), url('Example.ttf') format('truetype'); } ``` However, the suffix is not currently passed to esbuild and plugins may want to use this suffix for something. Previously plugins had to add their own `onResolve` handler if they wanted to use the query suffix. With this release, the suffix can now be returned by plugins from `onResolve` and is now passed to plugins in `onLoad`: ```js let examplePlugin = { name: 'example', setup(build) { build.onResolve({ filter: /.*/ }, args => { return { path: args.path, suffix: '?#iefix' } }) build.onLoad({ filter: /.*/ }, args => { console.log({ path: args.path, suffix: args.suffix }) }) }, } ``` The suffix is deliberately not included in the path that's provided to plugins because most plugins won't know to handle this strange edge case and would likely break. Keeping the suffix out of the path means that plugins can opt-in to handling this edge case if they want to, and plugins that aren't aware of this edge case will likely still do something reasonable.Configuration
📅 Schedule: At any time (no schedule defined).
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR has been generated by WhiteSource Renovate. View repository job log here.