Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This is a PR for version 0.10.0, which is a release that contains the following breaking changes:
No longer support
module
orexports
in an ESM file (fixes Presence of "module" or "exports" intrisics in an ESM module forces output to convert named exports into export default #769)This removes support for using CommonJS exports in a file with ESM exports. Previously this worked by converting the ESM file to CommonJS and then mixing the CommonJS and ESM exports into the same
exports
object. But it turns out that supporting this is additional complexity for the bundler, so it has been removed. It's also not something that works in real JavaScript environments since modules will never support both export syntaxes at once.Note that this doesn't remove support for using
require
in ESM files. Doing this still works (and can be made to work in a real ESM environment by assigning toglobalThis.require
). This also doesn't remove support for usingimport
in CommonJS files. Doing this also still works.No longer change
import()
torequire()
(fixes Unable to preserve dynamic imports withtransform
ortransformSync
API #1029)Previously esbuild's transform for
import()
matched TypeScript's behavior, which is to transform it intoPromise.resolve().then(() => require())
when the current output format is something other than ESM. This was done when an import is external (i.e. not bundled), either due to the expression not being a string or due to the string matching an external import path.With this release, esbuild will no longer do this. Now
import()
expressions will be preserved in the output instead. These expressions can be handled in non-ESM code by arranging for theimport
identifier to be a function that imports ESM code. This is how node works, so it will now be possible to useimport()
with node when the output format is something other than ESM.Run-time
export * as
statements no longer convert the file to CommonJSCertain
export * as
statements require a bundler to evaluate them at run-time instead of at compile-time like the JavaScript specification. This is the case when re-exporting symbols from an external file and a file in CommonJS format.Previously esbuild would handle this by converting the module containing the
export * as
statement to CommonJS too, since CommonJS exports are evaluated at run-time while ESM exports are evaluated at bundle-time. However, this is undesirable because tree shaking only works for ESM, not for CommonJS, and the CommonJS wrapper causes additional code bloat. Another upcoming problem is that top-level await cannot work within a CommonJS module because CommonJSrequire()
is synchronous.With this release, esbuild will now convert modules containing a run-time
export * as
statement to a special ESM-plus-dynamic-fallback mode. In this mode, named exports present at bundle time can still be imported directly by name, but any imports that don't match one of the explicit named imports present at bundle time will be converted to a property access on the fallback object instead of being a bundle error. These property accesses are then resolved at run-time and will be undefined if the export is missing.Initial support for bundling with top-level await (support for top level await #253)
Top-level await is a feature that lets you use an
await
expression at the top level (outside of anasync
function). Here is an example:Top-level await only works in ECMAScript modules, and does not work in CommonJS modules. This means that you must use an
import
statement or animport()
expression to import a module containing top-level await. You cannot userequire()
because it's synchronous while top-level await is asynchronous. There should be a descriptive error message when you try to do this.This initial release only has limited support for top-level await. It is only supported with the
esm
output format, but not with theiife
orcjs
output formats. In addition, the compilation is not correct in that two modules that both contain top-level await and that are siblings in the import graph will be evaluated in serial instead of in parallel. Full support for top-level await will come in a future release.Change whether certain files are interpreted as ESM or CommonJS (fixes Empty file bundles as
{ default: {} }
when imported viaimport *
#1043)The bundling algorithm currently doesn't contain any logic that requires flagging modules as CommonJS vs. ESM beforehand. Instead it handles a superset and then sort of decides later if the module should be treated as CommonJS vs. ESM based on whether the module uses the
module
orexports
variables and/or theexports
keyword.With this release, files that follow node's rules for module types will be flagged as explicitly ESM. This includes files that end in
.mjs
and files within a package containing"type": "module"
in the enclosingpackage.json
file. The CommonJSrequire
,module
, andexports
features will be unavailable in these files. This matters most for files without any exports, since then it's otherwise ambiguous what the module type is.In addition, files without exports should now accurately fall back to being considered CommonJS. They should now generate a
default
export of an empty object when imported using animport
statement, since that's what happens in node when you import a CommonJS file into an ESM file in node. Previously the default export could be undefined because these export-less files were sort of treated as ESM but with missing import errors turned into warnings instead.This is an edge case that rarely comes up in practice, since you usually never import things from a module that has no exports.
The main user-facing feature in this release is initial support for top-level await (only with the
esm
format, and only serial not parallel). The remaining changes are related to the ongoing linker rewrite and help unblock future linker improvements. These changes are being spread out over multiple releases instead of holding them all back into one big release to make the rollout of the new linker go more smoothly. Landing these linker changes incrementally gives them time to "bake" ahead of them being relied on by the new linker, and also helps avoid the overhead of constantly rebasing a large long-lived branch.