Repository navigation
fix(build): scope standalone type:module to worker dirs so server.js stays CJS - #10936
Merged
diegosouzapw merged 2 commits intoAug 21, 2026
Conversation
…stays CJS
The Next.js standalone entrypoint server.js is CommonJS (require/__dirname),
so assembleStandalone.mjs::patchStandalonePackageJson deliberately strips
"type":"module" from the standalone root package.json. The postbuild step
colocate-standalone.mjs then re-added "type":"module" to that same root to
make its esbuild'd ESM worker bundles (callLogArtifactWorker.js, onnxWorker.js)
load as ESM. Because postbuild runs last, the root ends up with type:module and
the container crashes on boot:
file:///app/server.js:1
const path = require('path')
ReferenceError: require is not defined in ES module scope
Node resolves module type from the nearest package.json, so instead of forcing
the whole standalone tree to ESM (which breaks server.js), write a scoped
{"type":"module"} package.json into each worker's own directory. The root stays
CommonJS for server.js while each worker keeps its ESM scope. No worker format
change, no root edit, and the no-clobber guard never overwrites a traced
package.json.
Refactors the script's body into main() + an exported writeEsmWorkerScopes()
helper (mirroring build-next-isolated.mjs's main-guard idiom) so the scoping
logic is unit-testable without a full next build.
Fixes cheaper-inference#10933. Regression from cheaper-inference#10836.
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes a Docker boot regression where the Next.js standalone server.js (CommonJS) was being parsed as ESM due to "type":"module" being re-added to the standalone root package.json during postbuild. The fix scopes {"type":"module"} to the specific worker directories so ESM worker bundles load correctly without forcing the entire standalone tree into ESM.
Changes:
- Refactors
scripts/build/colocate-standalone.mjsto write per-workerpackage.jsonESM scopes (writeEsmWorkerScopes) instead of mutating the standalone root manifest. - Adds an
OMNIROUTE_STANDALONE_DIRoverride seam and makes the script importable for unit testing (entrypoint guard + exported helper). - Adds a focused unit/regression test that proves CJS
server.jsand ESM worker.jscan coexist via nearest-package.jsonresolution.
Testing / Coverage (custom):
- Commands (reported in PR):
node --import tsx/esm --test tests/unit/build/colocate-standalone-esm-scope.test.ts - Changed/added tests:
tests/unit/build/colocate-standalone-esm-scope.test.ts - Coverage result: not provided in the PR description (custom)
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| scripts/build/colocate-standalone.mjs | Stops re-adding "type":"module" at the standalone root; instead writes no-clobber ESM scopes in worker directories and adds a test seam/entry guard. |
| tests/unit/build/colocate-standalone-esm-scope.test.ts | New regression test covering scoped ESM manifests, no root mutation, no-clobber behavior, and an end-to-end CJS+ESM coexistence check. |
| changelog.d/fixes/10936-standalone-server-cjs-esm-scope.md | Changelog entry documenting the Docker boot crash fix and the worker-dir scoping approach. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
diegosouzapw
merged commit Aug 21, 2026
10deb5c
into
cheaper-inference:release/v3.8.50
3 checks passed
backryun
added a commit
to backryun/OmniRoute
that referenced
this pull request
Aug 22, 2026
…NDALONE_DIR vars Three merged features read env vars that were never added to .env.example / ENVIRONMENT.md, breaking the env-doc contract gate (check-env-doc-sync + issue-7793 repro test) on release/v3.8.50: - KIMI_WEB_BASE_URL / KIMI_WEB_CHAT_URL — Kimi Web executor overrides (cheaper-inference#10944 moved the default to www.kimi.ai but never documented the override knobs) - OMNIROUTE_OIDC_DISABLE_PASSWORD_LOGIN (+ bare alias OIDC_DISABLE_PASSWORD_LOGIN) — OIDC-only login flag (cheaper-inference#10889) - OMNIROUTE_STANDALONE_DIR — build-time standalone output override (scripts/build/colocate-standalone.mjs, cheaper-inference#10936) check-env-doc-sync.mjs now reports "✓ Env / docs contract is in sync" and both sync tests pass 15/15.
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
…stays CJS (cheaper-inference#10936) Validado no worktree combinado: typecheck:core, changelog-integrity, complexity, cognitive-complexity, file-size, lint e teste focado (colocate-standalone-esm-scope) todos verdes. Fix real, correção de regressão introduzida por cheaper-inference#10836 (server.js CommonJS quebrando com type:module reintroduzido). CI vermelho é o base-red já rastreado em cheaper-inference#9985. Obrigado!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
The official
diegosouzapw/omniroute:nextDocker image crashes immediately on boot with:This is a CommonJS/ESM module-system conflict in the build, and it is a regression introduced by #10836. This PR fixes it at the source so the standalone
server.jsboots while the ESM worker bundles keep working.Fixes #10933.
Root cause
Two build steps make contradictory claims about the standalone
package.json:scripts/build/assembleStandalone.mjs→patchStandalonePackageJson()removes"type":"module"from the standalone rootpackage.json, on purpose, because the Next.js standalone entrypointserver.jsis CommonJS (require(),__dirname).scripts/build/colocate-standalone.mjs(the npmpostbuildhook, added in fix(build): ensure standalone package.json declares module type for Node 24 worker compatibility #10836) re-adds"type":"module"to that same root so its esbuild'd ESM worker bundles (callLogArtifactWorker.js,onnxWorker.js, both emitted with--format=esm) load as ESM.postbuildruns afterbuild, so step 2 wins. The standalone root ends up with"type":"module", Node then parses the CommonJSserver.jsas ESM, and it throws on the firstrequire().run-standalone.mjs→server-ws.mjs→await import("./server.js")surfaces the crash at boot.Fix
Node resolves a file's module system from the nearest
package.json. Instead of flipping the whole standalone tree to ESM (which breaksserver.js), scope{"type":"module"}to each worker's own directory:package.json→ stays CommonJS (notype), soserver.jsrunssrc/lib/usage/package.json→{"type":"module"}, socallLogArtifactWorker.jsruns as ESMopen-sse/services/compression/engines/llmlingua/package.json→{"type":"module"}, soonnxWorker.jsruns as ESM (only when the optional SLM deps are installed)This preserves #10836's intent (the ESM workers still load without a warning) while keeping
server.jsCommonJS. No worker format change, no root edit. The write is no-clobber, so it never overwrites apackage.jsonthat Next's trace already placed in a worker directory.The issue suggested renaming
server.js→server.cjs; that works too, but it touches the Next standalone entry contract (server-ws.mjs,run-standalone.mjs,dev/run-standalone.mjs) and several build/pack scripts. Scoping the worker dirs is the smaller, more contained change and leaves the entrypoint untouched.Changes
scripts/build/colocate-standalone.mjstype:modulere-add withwriteEsmWorkerScopes(), which writes a scoped{"type":"module"}into each worker directory.main()+ an exportedwriteEsmWorkerScopes()helper, guarded by theimport.meta.url === argv[1]run-check (same idiom asbuild-next-isolated.mjs), so the scoping logic is importable and unit-testable without a fullnext build.OMNIROUTE_STANDALONE_DIRoverride seam (mirrorswrite-build-sha.mjs/write-build-base-path.mjs).tests/unit/build/colocate-standalone-esm-scope.test.ts(new)type:modulelands in each worker dir, the rootpackage.jsonis never touched, and the write is no-clobber.server.jsand an ESMworker.jsside by side under the scoped layout to prove the two module systems coexist (this is exactly what the bug broke).Testing
Sibling build tests stay green (
tests/unit/build/assemble-standalone.test.ts,tests/unit/colocate-optionals.test.ts: 13/13). I also rebuilt therunner-baseimage from this branch and confirmed the container boots past the previous crash and serves the dashboard.Notes
release/v3.8.50perCONTRIBUTING.md.changelog.d/fixes/.