Releases: evanw/esbuild
v0.8.57
-
Fix overlapping chunk names when code splitting is active (#928)
Code splitting chunks use a content hash in their file name. This is good for caching because it means the file name is guaranteed to change if the chunk contents change, and the file name is guaranteed to stay the same if the chunk contents don't change (e.g. someone only modifies a comment). However, using a pure content hash can cause bugs if two separate chunks end up with the same contents.
A high-level example would be two identical copies of a library being accidentally collapsed into a single copy. While this results in a smaller bundle, this is incorrect because each copy might need to have its own state and so must be represented independently in the bundle.
This release fixes this issue by mixing additional information into the file name hash, which is no longer a content hash. The information includes the paths of the input files as well as the ranges of code within the file that are included in the chunk. File paths are used because they are a stable file identifier, but the relative path is used with
/
as the path separator to hopefully eliminate cross-platform differences between Unix and Windows. -
Fix
--keep-names
for lowered class fieldsAnonymous function expressions used in class field initializers are automatically assigned a
.name
property in JavaScript:class Example { field1 = () => {} static field2 = () => {} } assert(new Example().field1.name === 'field1') assert(Example.field2.name === 'field2')
This usually doesn't need special handling from esbuild's
--keep-names
option because esbuild doesn't modify field names, so the.name
property will not change. However, esbuild will relocate the field initializer if the configured language target doesn't support class fields (e.g.--target=es6
). In that case the.name
property wasn't preserved even when--keep-names
was specified. This bug has been fixed. Now the.name
property should be preserved in this case as long as you enable--keep-names
. -
Enable importing certain data URLs in CSS and JavaScript
You can now import data URLs of type
text/css
using a CSS@import
rule and import data URLs of typetext/javascript
andapplication/json
using a JavaScriptimport
statement. For example, doing this is now possible:import 'data:text/javascript,console.log("hello!");'; import _ from 'data:application/json,"world!"';
This is for compatibility with node which supports this feature natively. Importing from a data URL is sometimes useful for injecting code to be evaluated before an external import without needing to generate a separate imported file.
v0.8.56
-
Fix a discrepancy with esbuild's
tsconfig.json
implementation (#913)If a
tsconfig.json
file contains a"baseUrl"
value and"extends"
anothertsconfig.json
file that contains a"paths"
value, the base URL used for interpreting the paths should be the overridden value. Previously esbuild incorrectly used the inherited value, but with this release esbuild will now use the overridden value instead. -
Work around the Jest testing framework breaking node's
Buffer
API (#914)Running esbuild within a Jest test fails because Jest causes
Buffer
instances to not be consideredUint8Array
instances, which then breaks the code esbuild uses to communicate with its child process. More info is here: jestjs/jest#4422. This release contains a workaround that copies eachBuffer
object into aUint8Array
object when this invariant is broken. That should prevent esbuild from crashing when it's run from within a Jest test. -
Better handling of implicit
main
fields inpackage.json
If esbuild's automatic
main
vs.module
detection is enabled forpackage.json
files, esbuild will now useindex.js
as an implicitmain
field if themain
field is missing butindex.js
is present. This means if apackage.json
file only contains amodule
field but not amain
field and the package is imported using both an ESMimport
statement and a CommonJSrequire
call, theindex.js
file will now be picked instead of the file in themodule
field.
v0.8.55
-
Align more closely with node's
default
import behavior for CommonJS (#532)Note: This could be considered a breaking change or a bug fix depending on your point of view.
Importing a CommonJS file into an ESM file does not behave the same everywhere. Historically people compiled their ESM code into CommonJS using Babel before ESM was supported natively. More recently, node has made it possible to use ESM syntax natively but to still import CommonJS files into ESM. These behave differently in many ways but one of the most unfortunate differences is how the
default
export is handled.When you import a normal CommonJS file, both Babel and node agree that the value of
module.exports
should be stored in the ESM import nameddefault
. However, if the CommonJS file used to be an ESM file but was compiled into a CommonJS file, Babel will set the ESM import nameddefault
to the value of the original ESM export nameddefault
while node will continue to set the ESM import nameddefault
to the value ofmodule.exports
. Babel detects if a CommonJS file used to be an ESM file by the presence of theexports.__esModule = true
marker.This is unfortunate because it means there is no general way to make code work with both ecosystems. With Babel the code
import * as someFile from './some-file'
can access the originaldefault
export withsomeFile.default
but with node you need to usesomeFile.default.default
instead. Previously esbuild followed Babel's approach but starting with this release, esbuild will now try to use a blend between the Babel and node approaches.This is the new behavior: importing a CommonJS file will set the
default
import tomodule.exports
in all cases except whenmodule.exports.__esModule && "default" in module.exports
, in which case it will fall through tomodule.exports.default
. In other words: in cases where the default import was previouslyundefined
for CommonJS files whenexports.__esModule === true
, the default import will now bemodule.exports
. This should hopefully keep Babel cross-compiled ESM code mostly working but at the same time now enable some node-oriented code to start working.If you are authoring a library using ESM but shipping it as CommonJS, the best way to avoid this mess is to just never use
default
exports in ESM. Only use named exports with names other thandefault
. -
Fix bug when ESM file has empty exports and is converted to CommonJS (#910)
A file containing the contents
export {}
is still considered to be an ESM file even though it has no exports. However, if a file containing this edge case is converted to CommonJS internally during bundling (e.g. when it is the target ofrequire()
), esbuild failed to mark theexports
symbol from the CommonJS wrapping closure as used even though it is actually needed. This resulted in an output file that crashed when run. Theexports
symbol is now considered used in this case, so the bug has been fixed. -
Avoid introducing
this
for imported function callsIt is possible to import a function exported by a CommonJS file into an ESM file like this:
import {fn} from './cjs-file.js' console.log(fn())
When you do this, esbuild currently transforms your code into something like this:
var cjs_file = __toModule(require("./cjs-file.js")); console.log(cjs_file.fn());
However, doing that changes the value of
this
observed by the exportfn
. The property accesscjs_file.fn
is in the syntactic "call target" position so the value ofthis
becomes the value ofcjs_file
. With this release, esbuild will now use a different syntax in this case to avoid passingcjs_file
asthis
:var cjs_file = __toModule(require("./cjs-file.js")); console.log((0, cjs_file.fn)());
This change in esbuild mirrors a similar recent TypeScript compiler change, and also makes esbuild more consistent with Babel which already does this transformation.
v0.8.54
-
Fix ordering issue with private class methods (#901)
This release fixes an ordering issue with private class fields where private methods were not available inside class field initializers. The issue affected code such as the following when the compilation target was set to
es2020
or lower:class A { pub = this.#priv; #priv() { return 'Inside #priv'; } } assert(new A().pub() === 'Inside #priv');
With this release, code that does this should now work correctly.
-
Fix
--keep-names
for private class membersNormal class methods and class fields don't need special-casing with esbuild when the
--keep-names
option is enabled because esbuild doesn't rename property names and doesn't transform class syntax in a way that breaks method names, so the names are kept without needing to generate any additional code.However, this is not the case for private class methods and private class fields. When esbuild transforms these for
--target=es2020
and earlier, the private class methods and private class field initializers are turned into code that uses aWeakMap
or aWeakSet
for access to preserve the privacy semantics. This ends up breaking the.name
property and previously--keep-names
didn't handle this edge case.With this release,
--keep-names
will also preserve the names of private class methods and private class fields. That means code like this should now work with--keep-names --target=es2020
:class Foo { #foo() {} #bar = () => {} test() { assert(this.#foo.name === '#foo') assert(this.#bar.name === '#bar') } }
-
Fix cross-chunk import paths (#899)
This release fixes an issue with the
--chunk-names=
feature where import paths in between two different automatically-generated code splitting chunks were relative to the output directory instead of relative to the importing chunk. This caused an import failure with the imported chunk if the chunk names setting was configured to put the chunks into a subdirectory. This bug has been fixed. -
Remove the guarantee that direct
eval
can access imported symbolsUsing direct
eval
when bundling is not a good idea because esbuild must assume that it can potentially reach anything in any of the containing scopes. Using directeval
has the following negative consequences:-
All names in all containing scopes are frozen and are not renamed during bundling, since the code in the direct
eval
could potentially access them. This prevents code in all scopes containing the call to directeval
from being minified or from being removed as dead code. -
The entire file is converted to CommonJS. This increases code size and decreases performance because exports are now resolved at run-time instead of at compile-time. Normally name collisions with other files are avoided by renaming conflicting symbols, but direct
eval
prevents symbol renaming so name collisions are prevented by wrapping the file in a CommonJS closure instead. -
Even with all of esbuild's special-casing of direct
eval
, referencing an ESMimport
from directeval
still doesn't necessarily work. ESM imports are live bindings to a symbol from another file and are represented by referencing that symbol directly in the flattened bundle. That symbol may use a different name which could break directeval
.
I recently realized that the last consequence of direct
eval
(the problem about not being able to referenceimport
symbols) could cause subtle correctness bugs. Specifically esbuild tries to prevent the imported symbol from being renamed, but doing so could cause name collisions that make the resulting bundle crash when it's evaluated. Two files containing directeval
that both import the same symbol from a third file but that import it with different aliases create a system of unsatisfiable naming constraints.So this release contains these changes to address this:
-
Direct
eval
is no longer guaranteed to be able to access imported symbols. This means imported symbols may be renamed or removed as dead code even though a call to directeval
could theoretically need to access them. If you need this to work, you'll have to store the relevant imports in a variable in a nested scope and move the call to directeval
into that nested scope. -
Using direct
eval
in a file in ESM format is now a warning. This is because the semantics of directeval
are poorly understood (most people don't intend to use directeval
at all) and because the negative consequences of bundling code with directeval
are usually unexpected and undesired. Of the few valid use cases for directeval
, it is usually a good idea to rewrite your code to avoid using directeval
in the first place.For example, if you write code that looks like this:
export function runCodeWithFeatureFlags(code) { let featureFlags = {...} eval(code) // "code" should be able to access "featureFlags" }
you should almost certainly write the code this way instead:
export function runCodeWithFeatureFlags(code) { let featureFlags = {...} let fn = new Function('featureFlags', code) fn(featureFlags) }
This still gives
code
access tofeatureFlags
but avoids all of the negative consequences of bundling code with directeval
.
-
v0.8.53
-
Support chunk and asset file name templates (#733, #888)
This release introduces the
--chunk-names=
and--asset-names=
flags. These flags let you customize the output paths for chunks and assets within the output directory. Each output path is a template and currently supports these placeholders:[name]
: The original name of the file. This will bechunk
for chunks and will be the original file name (without the extension) for assets.[hash]
: The content hash of the file. This is not necessarily stable across different esbuild versions but will be stable within the same esbuild version.
For example, if you want to move all chunks and assets into separate subdirectories, you could use
--chunk-names=chunks/[name]-[hash]
and--asset-names=assets/[name]-[hash]
. Note that the path template should not include the file extension since the file extension is always automatically added to the end of the path template.Additional name template features are planned in the future including a
[dir]
placeholder for the relative path from theoutbase
directory to the original input directory as well as an--entry-names=
flag, but these extra features have not been implemented yet. -
Handle
this
in class static field initializers (#885)When you use
this
in a static field initializer inside aclass
statement or expression, it references the class object itself:class Foo { static Bar = class extends this { } } assert(new Foo.Bar() instanceof Foo)
This case previously wasn't handled because doing this is a compile error in TypeScript code. However, JavaScript does allow this so esbuild needs to be able to handle this. This edge case should now work correctly with this release.
-
Do not warn about dynamic imports when
.catch()
is detected (#893)Previously esbuild avoids warning about unbundled
import()
expressions when using thetry { await import(_) }
pattern, since presumably thetry
block is there to handle the run-time failure of theimport()
expression failing. This release adds some new patterns that will also suppress the warning:import(_).catch(_)
,import(_).then(_).catch(_)
, andimport(_).then(_, _)
. -
CSS namespaces are no longer supported
CSS namespaces are a weird feature that appears to only really be useful for styling XML. And the world has moved on from XHTML to HTML5 so pretty much no one uses CSS namespaces anymore. They are also complicated to support in a bundler because CSS namespaces are file-scoped, which means:
-
Default namespaces can be different in different files, in which case some default namespaces would have to be converted to prefixed namespaces to avoid collisions.
-
Prefixed namespaces from different files can use the same name, in which case some prefixed namespaces would need to be renamed to avoid collisions.
Instead of implementing all of that for an extremely obscure feature, CSS namespaces are now just explicitly not supported. The code to handle
@namespace
has been removed from esbuild. This will likely not affect anyone, especially because bundling code using CSS namespaces with esbuild didn't even work correctly in the first place. -
v0.8.52
-
Fix a concurrent map write with the
--inject:
feature (#878)This release fixes an issue where esbuild could potentially crash sometimes with a concurrent map write when using injected files and entry points that were neither relative nor absolute paths. This was an edge case where esbuild's low-level file subsystem was being used without being behind a mutex lock. This regression was likely introduced in version 0.8.21. The cause of the crash has been fixed.
-
Provide
kind
toonResolve
plugins (#879)Plugins that add
onResolve
callbacks now have access to thekind
parameter which tells you what kind of import is being resolved. It will be one of the following values:-
"entry-point"
in JS (api.ResolveEntryPoint
in Go)An entry point provided by the user
-
"import-statement"
in JS (api.ResolveJSImportStatement
in Go)A JavaScript
import
orexport
statement -
"require-call"
in JS (api.ResolveJSRequireCall
in Go)A JavaScript call to
require(...)
with a string argument -
"dynamic-import"
in JS (api.ResolveJSDynamicImport
in Go)A JavaScript
import(...)
expression with a string argument -
"require-resolve"
in JS (api.ResolveJSRequireResolve
in Go)A JavaScript call to
require.resolve(...)
with a string argument -
"import-rule"
in JS (api.ResolveCSSImportRule
in Go)A CSS
@import
rule -
"url-token"
in JS (api.ResolveCSSURLToken
in Go)A CSS
url(...)
token
These values are pretty much identical to the
kind
field in the JSON metadata file. -
v0.8.51
-
The stderr log format now contains line numbers after file names (#865)
Error messages in stderr now have a line and column number after the file name.
Before:
> src/structs/RTree.js: warning: Duplicate key "compareMinX" in object literal 469 │ compareMinX: function (a, b) ╵ ~~~~~~~~~~~ src/structs/RTree.js: note: The original "compareMinX" is here 206 │ compareMinX: compareNodeMinX, ╵ ~~~~~~~~~~~
After:
> src/structs/RTree.js:469:4: warning: Duplicate key "compareMinX" in object literal 469 │ compareMinX: function (a, b) ╵ ~~~~~~~~~~~ src/structs/RTree.js:206:4: note: The original "compareMinX" is here 206 │ compareMinX: compareNodeMinX, ╵ ~~~~~~~~~~~
This should make log messages slightly easier to parse if you want to parse stderr instead of using esbuild's API. Previously you needed a multi-line regular expression to get the line number, but now that the line number is duplicated in two places you should only need a single-line regular expression.
Note that this is still the hacky way to get error information and is potentially unstable, since it will break if the log format changes. Log messages are mainly intended for humans. The straightforward and stable way to do this is still to use esbuild's API, which returns log messages as an array of objects.
-
Allow
--define
withimport.meta
The
--define
feature lets you replace specific identifiers and member expression chains with compile-time constants. However, it previously didn't work withimport.meta
because this is a special case in the grammar. Theimport
keyword is not actually an identifier expression. This distinction isn't helpful though, and it's not unreasonable to want to use the--define
feature to replaceimport.meta
properties too.With this release, it's now possible to use e.g.
--define:import.meta.foo=123
to replace specific properties accessed off of theimport.meta
object as well as to use e.g.--define:import.meta={\"foo\":123}
to substitute the entireimport.meta
expression with something else. -
Fix a race condition with multiple injected files (#871)
Using multiple injected files could cause a data race that trips Go's race detector. The data race has been fixed in this release. The fix was contributed by @Deleplace.
-
Change
--serve
behavior to serve on all interfaces (#866)The default address for the
--serve
flag has changed from127.0.0.1
(serve on the loopback interface) to0.0.0.0
(serve on all interfaces). You can still manually specify either one using--serve=127.0.0.1:8000
or--serve=0.0.0.0:8000
. This just changes the default behavior that happens when you pass--serve
with no host address (or when you just use the--servedir=
flag without--serve=
).In addition, you can now also specify an IPv6 address. Previously there was a parsing issue that prevented this. For example, you can pass
--serve=[::1]:8000
to serve on the loopback interface and--serve=[::]:8000
to serve on all interfaces. -
Change the import resolution rules of absolute paths (#862)
Previously absolute paths were considered to be pre-resolved by the resolver (in contrast to relative and package paths, which need to be converted to an absolute path). This meant that absolute paths which did not actually exist caused a failure in the loader when it tried to load the path instead of in the resolver when it tried to resolve the path.
With the previous change in version 0.8.47 to support removing URL query and/or hash parameters from the path, path resolution can now be run multiple times. If path resolution fails and the path contains a
?
and/or#
, path resolution is re-run with the URL query/hash parameters removed. It is problematic to consider absolute paths to be pre-resolved because it means that paths containing query/hash parameters make the loader try to load the wrong path, and do not run the resolver again with the parameter suffix removed.In this release, esbuild will now validate absolute paths in the resolver. So invalid paths will now fail in the resolver and retry without the parameter suffix instead of failing in the loader, which correctly handles a parameter suffix on absolute paths. In addition, this release now handles implicit file extensions on absolute paths. This makes esbuild a more accurate copy of node's module resolution algorithm, which does this as well.
-
Output files in
metafile
now haveentryPoint
(#711)There is now an optional
entryPoint
property on each output file in the JSON metadata file generated with the--metafile=
flag. It is only present for output files that are the bundled results of entry point files, and contains the path name of the corresponding input entry point file. This property is not present on other kinds of output files (e.g. code splitting chunks). This feature was contributed by @remorses.
v0.8.50
-
Using direct
eval
now pulls inmodule
andexports
Use of direct
eval
forces the file to become a CommonJS module and disables dead code elimination in the entire file. The CommonJS closure is necessary to avoid name collisions with other modules, sinceeval
means symbols in the file can no longer be renamed to avoid collisions.However, the CommonJS
module
andexports
variables that are arguments to the closure previously weren't considered to be used in this scenario, meaning they may be omitted as dead code for size reasons. This could cause code insideeval
to behave incorrectly. Now use of directeval
automatically counts as a use of bothmodule
andexports
so these variables should now always be present in this case. -
Always remove all
"use asm"
directives (#856)The asm.js subset of JavaScript has complicated validation rules that are triggered by this directive. The parser and code generator in esbuild was not designed with asm.js in mind and round-tripping asm.js code through esbuild will very likely cause it to no longer validate as asm.js. When this happens, V8 prints a warning and people don't like seeing the warning. The warning looks like this:
(node:58335) V8: example.js:3 Invalid asm.js: Unexpected token (Use `node --trace-warnings ...` to show where the warning was created)
I am deliberately not attempting to preserve the validity of asm.js code because it's a complicated legacy format and it's obsolete now that WebAssembly exists. By removing all
"use asm"
directives, the code will just become normal JavaScript and work fine without generating a warning. -
Fix a variable hoisting edge case (#857)
It is allowed to use a nested
var
hoisted declaration with the same name as a top-level function declaration. In that case the two symbols should merge and be treated as the same symbol:async function x() {} { var x; }
The parser previously allowed this for regular functions but not for async or generator functions. Now with this release, this behavior is also allowed for these special kinds of functions too.
-
Remove empty CSS rules when minifying (#851)
Empty rules with no content such as
div {}
are now removed when CSS is minified. This change was contributed by @susiwen8.
v0.8.49
-
Work around a problem with
pnpm
andNODE_PATH
(#816)In version 0.8.43, esbuild added support for node's
NODE_PATH
environment variable which contains a list of global folders to use during path resolution. However, this causes a problem when esbuild is installed with pnpm, an alternative JavaScript package manager. Specifically pnpm adds a bogus path toNODE_PATH
that doesn't exist but that has a file as a parent directory. Previously this caused esbuild to fail with the errornot a directory
. Now with this release, esbuild will ignore this bogus path instead of giving an error. -
Add more names to the global no-side-effect list (#842)
This release adds almost all known globals from the browser and node to the list of known globals. Membership in this list means accessing the global is assumed to have no side effects. That means tree shaking is allowed to remove unused references to these globals. For example, since
HTMLElement
is now in the known globals list, the following class will now be removed when unused:class MyElement extends HTMLElement { }
In addition, membership in this list relaxes ordering constraints for the purposes of minification. It allows esbuild to reorder references to these globals past other expressions. For example, since
console.log
is now in the known globals list, the following simplification will now be performed during minification:// Original export default (a) => { if (a) console.log(b); else console.log(c) } // Minified (previous release) export default (a) => { a ? console.log(b) : console.log(c); }; // Minified (this release) export default (a) => { console.log(a ? b : c); };
This transformation is not generally safe because the
console.log
property access might evaluate code which could potentially change the value ofa
. This is only considered safe in this instance becauseconsole.log
is now in the known globals list.Note that membership in this list does not say anything about whether the function has side effects when called. It only says that the identifier has no side effects when referenced. So
console.log()
is still considered to have side effects even thoughconsole.log
is now considered to be free of side effects.The following globals are not on the list and are considered to have side effects:
scrollX
scrollY
innerWidth
innerHeight
pageXOffset
pageYOffset
localStorage
sessionStorage
Accessing layout-related properties can trigger a layout and accessing storage-related properties can throw an exception if certain privacy settings are enabled. Both of these behaviors are considered side effects.
-
Fix a TypeScript parser regression (#846)
Restrictions on array and object destructuring patterns in the previous release introduced a regression where arrays or objects in TypeScript code could fail to parse if they were wrapped in a double layer of parentheses. This was due to the speculative parsing of arrow function arguments. The regression has been fixed.
-
Add the Go-specific
cli.ParseServeOptions()
API (#834)This API is specifically for people trying to emulate esbuild's CLI in Go. It lets you share esbuild's logic of parsing the
--serve=
and--servedir=
flags. Use it like this:serveOptions, args, err := cli.ParseServeOptions([]string{ "--serve=8000", }) buildOptions, err := cli.ParseBuildOptions(args) result := api.Serve(serveOptions, buildOptions)
v0.8.48
-
Fix some parsing edge cases (#835)
This release fixes the following edge cases:
-
Code using
in
inside a template literal inside a for loop initializer such asfor (let x = `${a in b ? '0' : '1'}`; false; );
is now allowed. Previously thein
operator was incorrectly considered to be part of a for-in loop. -
In TypeScript, it's not valid to have a newline in between the
async
and the<
tokens inside the codeasync <T>() => {}
. Previously this was incorrectly treated as an asynchronous arrow function expression. -
Code of the form
new async()
must construct the function calledasync
. Previously this was incorrectly treated asnew (async())()
instead due to the speculative parsing of asynchronous arrow functions. -
Code of the form
new async () => {}
must not be allowed. Previously this was incorrectly allowed since the speculative parsing of asynchronous arrow functions did not check the precedence level. -
It's not valid to start an initializer expression in a for-of loop with the token
let
such asfor (let.foo of bar) {}
. This is now forbidden. In addition, the code generator now respects this rule sofor ((let.foo) of bar) {}
is now printed asfor ((let).foo of bar) {}
. -
Array and object binding patterns do not allow a comma after rest elements, so code such as
[...a, b] = [c]
is invalid. This case is correctly handled by esbuild. However, it's possible to have both an array or object binding pattern and an array or object literal on the left-hand side of a destructuring assignment such as[[...a, b].c] = [d]
. In that case it should be allowed for a comma to come after the spread element in the array or object literal expression. Previously this was incorrectly treated as an error by esbuild. -
It's technically allowed (although perhaps not ever actually useful) to call
super()
from within a default argument initializer like this:class Derived extends Base { constructor(arg = super()) { } }
Previously esbuild did not permit this, which is incorrect. Doing this is now permitted.
-
It is an error to use
arguments
in a class field initializer such asclass { x = arguments[0] }
, but it is not an error to usearguments
in a computed class property name such asclass { [arguments[0]] = x }
or inside TypeScript decorators such asclass { @decorator(arguments[0]) x() {} }
. Previously all of these cases were an error in esbuild, which is incorrect. Usingarguments
inside computed class property names and TypeScript decorators is now allowed. -
It is not permitted to use a function declaration inside an if statement such as
if (0) function f() {}
in strict mode. Previously this was allowed, but this is now forbidden. -
It is not permitted to re-declare a generator and/or asynchronous function declaration inside a block scope:
// This is allowed function *a() {} function *a() {} // This is allowed function f() { function *b() {} function *b() {} } // This is not allowed { function *c() {} function *c() {} }
The parser now enforces this rule.
-
Legacy octal escape sequences are octal escape sequences other than
\0
with a single zero. These are forbidden in untagged template literals and in all strings in strict mode code. Previously esbuild didn't enforce this rule, but it is now enforced. -
Technically the directive prologue is allowed to contain multiple directives, so strict mode should still be applied even if a
"use strict";
directive is preceded by another directive. For example,"use \000"; "use strict";
should be a syntax error because strict mode is active. This technicality has now been implemented. -
It is supposed to be a syntax error if a use strict directive is inside a function with a non-simple parameter list, such as
(x = 1) => { 'use strict' }
. Previously esbuild allowed this code, but now this code is a syntax error. -
It is forbidden for a template literal tag to be an optional chain such as
a?.b`c`
. This rule is now enforced by esbuild, so code like this is now a syntax error. In addition, the code generator now avoids generating this syntax by wrapping any optional chain template literal tags in parentheses. -
According to the standard, all code inside a class statement or expression should be in strict mode. Previously esbuild treated code inside a class as the same strict mode status as the surrounding code, but now code in a class is always interpreted as strict mode code.
-
Duplicate bindings in the same parameter list are not allowed if the parameter list isn't simple, such as in the code
function f(a, [a]) {}
, or if the parameter list belongs to an arrow function or a method. This rule is now enforced by esbuild's parser, so doing this is now a syntax error. -
Array and object destructuring patterns are only valid if they are not surrounded by parentheses. Previously esbuild incorrectly allowed code such as
([]) = []
and({}) = {}
. This invalid code is now a syntax error. -
It is now an error to use the shorthand property syntax
({yield})
inside a generator and({await})
inside an asynchronous function. Previously those cases were incorrectly allowed. -
A newline in between
async
and a method name is no longer allowed. Instead, this is a syntax error inside an object literal and a class field inside a class body.
-
-
Remove the local web server feature from the WebAssembly package (#836)
This feature didn't work anyway (maybe sockets don't work with Go's WebAssembly target?) and including it added around 3mb of unnecessary extra code to the WebAssembly module file. Removing this brings the size of the WebAssembly module from around 11mb down to 8.3mb.