Repository navigation
Load modules containing top-level await through the existing synchronous API:
const load = require("esm-sync")(module)
const { client } = load("./client.mjs")
// The module and its asynchronous dependencies have finished evaluating.Asynchronous modules
- Receive fully evaluated exports from modules with top-level
await, including transitive dependencies, cycles, and dynamic imports. Live bindings and module identity are preserved; failed imports retain the original thrown value. - Use module-body
for await...of,using, andawait using, with iterator closing and resource disposal on abrupt exits. - Use import attributes, text imports, deferred imports, and string-named exports. Binding identity and ambiguous star re-exports are handled correctly.
- Import modules that declare their own
require, includingconst require = createRequire(import.meta.url).
Jest interoperability
- CommonJS dependencies loaded through
esm-syncshare constructors, fixing affectedinstanceofchecks and js-yaml schema construction. jest.resetModules()and independentjest.isolateModules()callbacks refresh loader-owned graphs, keeping ESM namespaces and CommonJS dependencies consistent. Retained loader factories and require functions can be reused across scopes.- Non-enumerable globals and lazy getters survive Jest VM context creation. This fixes missing
DOMExceptionerrors when loading dependencies such as Undici and@kubernetes/client-nodeon affected Node versions. - Jest 26 inherits modules already loaded in the outer registry; the loader follows that host behaviour rather than forcing those modules to reevaluate.
Installation and the optional native bridge
Published JavaScript is ready to use without a local build. Ordinary imports and microtask-settled awaits use the JavaScript loader. Synchronous awaits that need timers or I/O require a compatible native bridge on the initial CommonJS startup stack. The bridge targets Node 22 and newer and is specific to the operating system, architecture, and Node ABI.
The install hook reuses a valid bundled bridge or attempts to compile one using matching Node headers and a C++20 compiler. Skipping dependency build scripts keeps compatible bundled binaries usable. Without a bridge, timer/I/O-backed awaits fail with ERR_ESM_SYNC_ASYNC_PENDING; ordinary loading remains available. The loader does not compile or download a bridge during module loading.
pnpm may reject an unreviewed dependency build. Explicitly allow or deny the hook using allowBuilds or the workspace's permissions policy. To opt out:
allowBuilds:
esm-sync: falseESM_SYNC_AWAIT_TIMEOUT_MS sets the synchronous evaluation deadline (default: 5,000 ms). Active callbacks, Promise reactions, and worker contexts have re-entry restrictions. Unsafe synchronous re-entry raises ERR_ESM_SYNC_ASYNC_REENTRANT. See async module loading for supported contexts and error handling.
Compatibility and fixes
- The factory API and options remain
require("esm-sync")(module, options). - Package imports and physical
esm.js/index.jsentry paths retain matching TypeScript declarations, including for resolvers without package export maps. - Ordinary loading retains the declared Node
>=6engine range, including realms withoutglobalThis. New syntax and native-bridge features have additional runtime requirements. - Package export patterns, URL query/fragment handling, and disk-cache metadata validation are more robust.
Pull Requests
- feat: modernise toolings by @nktnet1 in #16
- test: restore upstream check, repl, test262, print, ci coverage by @nktnet1 in #17
- feat: test262 compliance by @nktnet1 in #18
- feat: support synchronous async module graphs by @nktnet1 in #19
- feat: typescript migration by @nktnet1 in #20
- build: migrate bundling from rspack to tsdown by @nktnet1 in #21
- build: use native minification and add registry smoke tests by @nktnet1 in #22
- feat(ci): automate beta and production npm releases by @nktnet1 in #24
- fix: preserve CommonJS constructor identity in Jest by @nktnet1 in #25
- fix: preserve Jest globals when recreating VM contexts by @nktnet1 in #26
Full Changelog: v3.3.7...v3.4.0