sea: support ESM entry point in SEA by joyeecheung · Pull Request #61813 · nodejs/node
This uses the new StartExecutionCallbackWithModule embedder API to support ESM entrypoint in SEA via a new configuration field `"mainFormat"`. The behavior currently aligns with the embedder API and is mostly in sync with the CommonJS entry point behavior, except that support for code caching and snapshot is left for follow-ups.
addaleax
added
request-ci
labels
joyeecheung
added
commit-queue
labels
aduh95 pushed a commit that referenced this pull request
This uses the new StartExecutionCallbackWithModule embedder API to support ESM entrypoint in SEA via a new configuration field `"mainFormat"`. The behavior currently aligns with the embedder API and is mostly in sync with the CommonJS entry point behavior, except that support for code caching and snapshot is left for follow-ups. PR-URL: #61813 Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
hyf0
mentioned this pull request
6 tasks
nodejs-github-bot added a commit that referenced this pull request
Notable changes: http2: * (SEMVER-MINOR) add http1Options for HTTP/1 fallback configuration (Amol Yadav) #61713 sea: * (SEMVER-MINOR) support ESM entry point in SEA (Joyee Cheung) #61813 sqlite: * mark as release candidate (Matteo Collina) #61262 stream: * (SEMVER-MINOR) rename `Duplex.toWeb()` type option to `readableType` (René) #61632 test_runner: * (SEMVER-MINOR) show interrupted test on SIGINT (Matteo Collina) #61676 PR-URL: #61922
aduh95 added a commit that referenced this pull request
Notable changes: http2: * (SEMVER-MINOR) add http1Options for HTTP/1 fallback configuration (Amol Yadav) #61713 sea: * (SEMVER-MINOR) support ESM entry point in SEA (Joyee Cheung) #61813 sqlite: * mark as release candidate (Matteo Collina) #61262 stream: * (SEMVER-MINOR) rename `Duplex.toWeb()` type option to `readableType` (René) #61632 test_runner: * (SEMVER-MINOR) show interrupted test on SIGINT (Matteo Collina) #61676 PR-URL: #61922
aduh95 added a commit that referenced this pull request
Notable changes: http2: * (SEMVER-MINOR) add http1Options for HTTP/1 fallback configuration (Amol Yadav) #61713 sea: * (SEMVER-MINOR) support ESM entry point in SEA (Joyee Cheung) #61813 sqlite: * mark as release candidate (Matteo Collina) #61262 stream: * (SEMVER-MINOR) rename `Duplex.toWeb()` type option to `readableType` (René) #61632 test_runner: * (SEMVER-MINOR) show interrupted test on SIGINT (Matteo Collina) #61676 PR-URL: #61922
aduh95 added a commit to aduh95/node that referenced this pull request
Notable changes: http2: * (SEMVER-MINOR) add http1Options for HTTP/1 fallback configuration (Amol Yadav) nodejs#61713 sea: * (SEMVER-MINOR) support ESM entry point in SEA (Joyee Cheung) nodejs#61813 sqlite: * mark as release candidate (Matteo Collina) nodejs#61262 stream: * (SEMVER-MINOR) rename `Duplex.toWeb()` type option to `readableType` (René) nodejs#61632 test_runner: * (SEMVER-MINOR) show interrupted test on SIGINT (Matteo Collina) nodejs#61676 PR-URL: nodejs#61922
ruyadorno pushed a commit that referenced this pull request
Notable changes: http2: * (SEMVER-MINOR) add http1Options for HTTP/1 fallback configuration (Amol Yadav) #61713 sea: * (SEMVER-MINOR) support ESM entry point in SEA (Joyee Cheung) #61813 sqlite: * mark as release candidate (Matteo Collina) #61262 stream: * (SEMVER-MINOR) rename `Duplex.toWeb()` type option to `readableType` (René) #61632 test_runner: * (SEMVER-MINOR) show interrupted test on SIGINT (Matteo Collina) #61676 PR-URL: #61922
sxzz
mentioned this pull request
himself65 added a commit to himself65/node that referenced this pull request
This uses the new StartExecutionCallbackWithModule embedder API to support ESM entrypoint in SEA via a new configuration field `"mainFormat"`. The behavior currently aligns with the embedder API and is mostly in sync with the CommonJS entry point behavior, except that support for code caching and snapshot is left for follow-ups. PR-URL: nodejs#61813 Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
himself65 added a commit to himself65/node that referenced this pull request
This uses the new StartExecutionCallbackWithModule embedder API to support ESM entrypoint in SEA via a new configuration field `"mainFormat"`. The behavior currently aligns with the embedder API and is mostly in sync with the CommonJS entry point behavior, except that support for code caching and snapshot is left for follow-ups. PR-URL: nodejs#61813 Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
himself65 pushed a commit to himself65/node that referenced this pull request
This uses the new StartExecutionCallbackWithModule embedder API to support ESM entrypoint in SEA via a new configuration field `"mainFormat"`. The behavior currently aligns with the embedder API and is mostly in sync with the CommonJS entry point behavior, except that support for code caching and snapshot is left for follow-ups. PR-URL: nodejs#61813 Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
nodejs-github-bot pushed a commit that referenced this pull request
The initial support for ESM entrypoint in SEA didn't support code cache. This patch implements that by following a path similar to how code cache in CJS SEA entrypoint is supported: at build time we generate the code cache from C++ and put it into the sea blob, and at runtime we consume it via a special case in compilation routines - for CJS this was CompileFunctionForCJSLoader, in the case of SourceTextModule, it's in Module::New. PR-URL: #62158 Refs: #61813 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
aduh95 pushed a commit that referenced this pull request
The initial support for ESM entrypoint in SEA didn't support code cache. This patch implements that by following a path similar to how code cache in CJS SEA entrypoint is supported: at build time we generate the code cache from C++ and put it into the sea blob, and at runtime we consume it via a special case in compilation routines - for CJS this was CompileFunctionForCJSLoader, in the case of SourceTextModule, it's in Module::New. PR-URL: #62158 Refs: #61813 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
aduh95 pushed a commit to himself65/node that referenced this pull request
This uses the new StartExecutionCallbackWithModule embedder API to support ESM entrypoint in SEA via a new configuration field `"mainFormat"`. The behavior currently aligns with the embedder API and is mostly in sync with the CommonJS entry point behavior, except that support for code caching and snapshot is left for follow-ups. PR-URL: nodejs#61813 Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
aduh95 pushed a commit to himself65/node that referenced this pull request
The initial support for ESM entrypoint in SEA didn't support code cache. This patch implements that by following a path similar to how code cache in CJS SEA entrypoint is supported: at build time we generate the code cache from C++ and put it into the sea blob, and at runtime we consume it via a special case in compilation routines - for CJS this was CompileFunctionForCJSLoader, in the case of SourceTextModule, it's in Module::New. PR-URL: nodejs#62158 Refs: nodejs#61813 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
aduh95 pushed a commit to himself65/node that referenced this pull request
The initial support for ESM entrypoint in SEA didn't support code cache. This patch implements that by following a path similar to how code cache in CJS SEA entrypoint is supported: at build time we generate the code cache from C++ and put it into the sea blob, and at runtime we consume it via a special case in compilation routines - for CJS this was CompileFunctionForCJSLoader, in the case of SourceTextModule, it's in Module::New. PR-URL: nodejs#62158 Refs: nodejs#61813 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
This was referenced
zkochan added a commit to pnpm/pnpm that referenced this pull request
## Summary `@pnpm/exe@11.0.0-rc.4` aborts on every invocation with: ``` node::sea::(anonymous namespace)::SeaDeserializer::Read() at ../src/node_sea.cc:174 Assertion failed: (format_value) <= (static_cast<uint8_t>(ModuleFormat::kModule)) ``` Two independent Node.js v25.7+ SEA regressions are responsible, both surfaced by the rc.4 bump of the embedded runtime from 25.6.1 to 25.9.0. This PR fixes both and adds a prepublish smoke test so a broken binary can't reach npm again. ## Root cause **1. SEA blob format changed in Node.js v25.7.0** ([nodejs/node#61813](nodejs/node#61813) added ESM-entry-point support and inserted a new `ModuleFormat` byte into the blob header). SEA blobs carry no version marker, so a blob written by one Node.js version can only be deserialized by a matching one. In rc.4, the CI host Node.js (25.6.1, pre-change) wrote the blob and it was embedded in a 25.9.0 runtime (post-change) — the deserializer reads a misaligned byte as `format_value`, exceeds `kModule`, `CHECK_LE` fires, `SIGABRT`. `resolveBuilderBinary()` was preferring `process.execPath` whenever the running Node supported `--build-sea`, never checking that its version matched the embedded runtime. **2. Node.js v25.7+ replaces the ambient `require` and `import()` inside a CJS SEA entry with embedder hooks** that only resolve built-in module names. The `pnpm.cjs` shim loaded `dist/pnpm.mjs` via `await import(pathToFileURL(...).href)`, which after the fix to (1) reached the CJS entry and then blew up with: ``` ERR_UNKNOWN_BUILTIN_MODULE: No such built-in module: file:///.../dist/pnpm.mjs at loadBuiltinModuleForEmbedder at importModuleDynamicallyForEmbedder ``` ## Changes - **`releasing/commands/src/pack-app/packApp.ts`** — `resolveBuilderBinary` now takes the resolved target runtime version and only reuses `process.execPath` when `process.version` exactly matches; otherwise it downloads a host-arch Node of the target version via the existing `ensureNodeRuntime` path. Added `PACK_APP_RUNTIME_TOO_OLD` for runtimes older than v25.5 (no `--build-sea`). Removed the now-unused `DEFAULT_BUILDER_SPEC` and the stale `fetch`/`nodeDownloadMirrors` args on the builder resolver. Help text / examples refreshed to drop `node@22` / `node@lts` references that would now be rejected. - **`pnpm/pnpm.cjs`** — loads `dist/pnpm.mjs` through `Module.createRequire(process.execPath)` instead of `await import(fileURL)`. `createRequire` returns a regular CJS loader that bypasses the SEA embedder hooks, and the pnpm bundle has no top-level await so synchronous `require` of ESM (Node 22+) loads it cleanly. No build-time paths are baked in — `process.execPath` is evaluated at runtime, verified by relocation-testing the darwin-arm64 SEA under `/tmp/`. - **`pnpm/artifacts/verify-binary.mjs`** (new) + `prepublishOnly` on every platform artifact — replaces the existence-only `test -f pnpm` gate with: 1. A **relocation-sensitivity check**: run the binary without `dist/` staged and confirm the failure mentions a path derived from `process.execPath`, not a build-time constant. Catches any future regression of (2). 2. A **smoke test**: stage a `dist → ../exe/dist` symlink (using `symlink-dir` so Windows junctions are handled transparently), exec `./pnpm -v`, assert the output is a SemVer 2 string. - Cross-platform targets (darwin/win32 artifacts on a Linux CI, or a libc mismatch) skip the exec with a log line and fall back to existence-only, so a musl artifact published from a glibc host still goes through. - Real `dist/` dirs (developer layout) are preserved; stale symlinks from aborted runs are replaced; created symlinks are cleaned up on exit. - **`pnpm/artifacts/exe/test/setup.test.ts`** — new `pnpm -v` execution test gated on both the platform binary and the staged bundle being present, so ordinary `pn compile` test runs skip cleanly instead of failing on a missing `dist/`.