Repository navigation
Make route CommonJS require work after bundling and name unsupported packages - #5472
kojiwakayama wants to merge 22 commits into
Conversation
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
📦 Client bundle boundary
A server module in a client graph aborts hydration in the browser. New leaks fail CI; known leaks are tracked in |
|
@codex review |
|
Score: 84/100. Fixes the compiled-binary
Mergeable_state is "blocked", so CI and review are still pending. I did not run the tests locally. Generated by Claude Code |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 81992113ae
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
esbuild reserves top-level require in ESM output, so the injected require never reached its __require helper on any runtime. Bundled project CommonJS could not require Node built-ins outside the compiled binary either. Refs #5471
|
@codex review |
|
Codex Review: Didn't find any major issues. Keep them coming! Reviewed commit: ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
The resolver error carried the host project path, and a .node addon was evaluated as JavaScript. Document supported npm package patterns for API routes. Refs #5471
|
@codex review |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ffb8fc06db
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ffb8fc06db
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
…terop - Keep compiled loader state in a private scope and fail the build when route code declares a remaining prologue binding. - Keep a bundled route hashbang on the first line; strip CJS hashbangs. - Resolve bare requires from the requiring module's directory. - Report an installed package with an unresolvable entry or subpath as such. - Give namespace and dynamic imports an ES module namespace with default. - Accept $ in rewritten import bindings. - Document lazy dynamic-import failures and exports-map limits. Refs #5471
|
@codex review |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 003421fed0
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…combined clauses - Reject only declarations of prologue names, not strings or properties. - Namespace default is the whole module.exports, __esModule included. - Keep code MODULE_NOT_FOUND on the sanitized resolution errors. - Rewrite every static import clause form, root or subpath, and side-effect imports. Refs #5471
|
@codex review |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 15f4a64362
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…free helpers - Rewrite compiled user dependency imports from parsed import statements, so import-like text in strings, templates and comments is untouched. - Prefix prologue helpers and temporaries with a prefix absent from the bundle, replacing the declaration check (and its regex escaping). - Cache one namespace object per CommonJS module. - Resolve relative and absolute require.resolve ids locally, checking containment before probing and naming a missing module by its id. Refs #5471
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1c7aaeeac5
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…re.cache/resolve.paths, node: built-in check, captured decoder intrinsics (#5471)
|
@codex review |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3077b9343b
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…its, canonical resolve, prototype-free tables (#5471)
|
@codex review |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 53da924716
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
… after postfix ++ as division (#5471)
|
@codex review |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e224578e45
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
… prototypes (#5471) Capture String, Function and URL prototype methods as uncurried functions, drop regex and Symbol-dispatching string methods, grow arrays by index, and resolve bare packages and module-relative file URLs without the runtime's node:module and node:url helpers, which call replaceable prototype methods.
|
@codex review |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 76f26858ed
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…llback in the CJS loader (#5471)
|
@codex review |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3346cd70c0
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const attributes = staticImportAttributes(masked, imported.a, imported.se); | ||
| const check = attributes | ||
| ? `${helperPrefix}validateImportOptions({ with: ${attributes} }, ${specifier}); ` | ||
| : ""; |
There was a problem hiding this comment.
Require JSON attributes for JSON package imports
When a compiled route statically imports a CommonJS package's JSON subpath without attributes, this conditional emits no validation and require() loads the JSON successfully; the dynamic path similarly skips validation when no options are supplied. Native ESM rejects both import data from "pkg/data.json" and import("pkg/data.json") unless type: "json" is present, so handlers can succeed only in the compiled binary instead of taking their expected failure path. Fresh evidence beyond the earlier module-type mismatch fix is the reverse mismatch: JSON targets are never required to carry the JSON attribute. Validate every rewritten import against its resolved target, including the no-options case.
AGENTS.md reference: AGENTS.md:L23-L25
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Not fixing this one. I tried it, and it breaks valid routes. esbuild drops with { type: "json" } from external imports before this rewrite runs. So a route that correctly writes import data from "pkg/data.json" with { type: "json" } reaches the rewriter without the attribute, and refusing it there fails that route. The existing test "rewrites static and dynamic package imports with attributes" failed when I enforced it. The rewrite cannot tell an omitted attribute from a dropped one, so it accepts a JSON module without one. A comment in a118734 explains this in both the validator and the rewrite. The opposite case, type: "json" on a non-JSON module, is still refused. Leaving this thread open for the owner's decision.
Posted by Claude Code (AI agent) on behalf of the PR author.
…kup to the project, absolute resolve ids, expression braces (#5471)
|
@codex review |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a118734177
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| // "do" and "else" start a statement; the other listed words take an | ||
| // expression. | ||
| previous = word === "do" || word === "else" ? ";" : __vf_regexAfterWord[word] === true ? "(" : "word"; | ||
| controlWord = word === "if" || word === "while" || word === "for" || word === "with"; |
There was a problem hiding this comment.
Preserve the control context across
for await
When a CommonJS dependency contains a valid loop such as for await (const value of values) /import(".\\/child.mjs")/.test(value), reading the intermediate await word clears controlWord, so the closing ) is treated as a value and the following slash as division. The scanner then rewrites the import(...) text inside the regex literal, corrupting the dependency. The earlier control-flow fix therefore still misses the distinct for await path; retain the for condition context through await.
AGENTS.md reference: AGENTS.md:L26-L28
Useful? React with 👍 / 👎.
| // the requiring module: the nearest package.json at or above its directory, | ||
| // inside the project. | ||
| function __vf_resolvePackageImport(id, parentDir) { | ||
| for (var dir = __vf_canonicalize(parentDir); ; dir = __vf_dirname(dir)) { |
There was a problem hiding this comment.
Honor node_modules boundaries in ancestor walks
When a manifest-less dependency under node_modules calls require("#x"), this loop crosses the node_modules boundary and incorrectly applies the project's package.json#imports; Node stops package-scope lookup at that boundary. The sibling __vf_resolveBare walk has the inverse form of the same defect: from /project/node_modules/bar it probes /project/node_modules/node_modules/foo before /project/node_modules/foo, so an otherwise ignored directory can shadow the real package. Make both ancestor walks node_modules-aware, stopping package-scope lookup and skipping duplicate node_modules candidates. Fresh evidence beyond the earlier package-import and bounded-lookup fixes is the manifest-less dependency path and the doubled node_modules candidate.
AGENTS.md reference: AGENTS.md:L23-L25
Useful? React with 👍 / 👎.
| throw unknown; | ||
| } | ||
| if (__vf_startsWith(id, "#")) return __vf_resolvePackageImport(id, parentDir); | ||
| var name = __vf_packageName(id); |
There was a problem hiding this comment.
Resolve package self-references before nested node_modules
When code inside package foo calls require("foo/sub") and foo/node_modules/foo also exists, this bare-package path searches the nested copy first and loads its subpath. Node resolves a package self-reference through the containing package's own name and exports before searching node_modules, so both require and require.resolve return the outer package in this scenario. Resolve the nearest containing package's self-reference before starting the node_modules walk to avoid loading the wrong package version.
Useful? React with 👍 / 👎.
|
Paused for a redesign and set to draft. Over 14 Codex review rounds this PR drew about 60 findings, and each round still finds new edge cases in the hand-written CommonJS loader. The replacement design is tracked in veryfront/veryfront-issue-inbox#4177. The tests in Posted by Claude Code (AI agent) on behalf of the PR author. |
|
|
Closing unmerged in favour of #5477, which bundles CommonJS dependencies of compiled-binary API routes with esbuild instead of loading them through a hand-written runtime loader (decision in veryfront/veryfront-issue-inbox#4177). The branch stays for reference. Posted by Claude Code (AI agent) on behalf of the PR author. |



Refs #5471
Change
Route
requireprologue (loader.ts)The route runtime shim used to inject
requireinto the esbuild bundle. esbuild reserves top-levelrequirein ESM output, so it renamed the injected binding and its__requirehelper never saw it. It also tree-shook__vf_interopDefault, because nothing referenced it until the compiled binary rewrote user dependency imports after bundling. As a result:import pg from "pg"failed withReferenceError: __vf_interopDefault is not defined. Named, namespace and dynamic imports failed withReferenceError: require is not defined.require("node:path")failed withDynamic require of "node:path" is not supported.The changes:
generateRouteRuntimeShim(routeSourceUrl)now injects only theWorkershim.prependRouteRequirePrologueaddsgenerateRouteRequirePrologue(projectDir, compiledBinary, helperPrefix)to the bundled, rewritten handler. On the compiled binary that is the compiled CJS loader; on other runtimes, acreateRequirebinding.chooseRouteHelperPrefix(bundle)picks the first helper prefix (__vf_,__vf1_, ...) none of whose helper names appears anywhere in the bundle. The same prefix goes to the import rewrite, the temporaries and both prologues, so route code can never collide with them.Compiled CJS loader (
external-import-rewriter.ts)require, the interop and namespace helpers and thenode:import aliases are module-level, under the chosen prefix.node_moduleswins over the root copy. Canonicalization and containment checks are unchanged.MODULE_NOT_FOUND, the error keepscode: "MODULE_NOT_FOUND"and reports eithernpm package "<name>" is not installed in this runtime's node_modulesornpm package "<name>" is installed but "<id>" could not be resolved, without host paths..nodefile throwsnative addon "<id>" cannot be loaded: native addons are not supported in this runtime.#!in a CommonJS source is commented out before evaluation.requireandrequire.resolve, probing Node's extensions, then a directory'spackage.jsonmain, then itsindex. Containment is checked before probing, and a missing module throwsCannot find module "<id>"withcode: "MODULE_NOT_FOUND".module.exportsas top-levelthis. The cache holds module records, so a circular require sees a reassignedmodule.exports, and a module whose evaluation throws is removed from it..node, so an extensionless native addon gets the native-addon error. A malformed localpackage.jsonis an error, not a fallback toindex..mjsfile from a CommonJS package fails withES module file "<id>" cannot be loaded with require.module.require,id,filename,pathandloaded.path.isAbsolute, so Windows drive-letter and UNC ids are paths.test,sqlite,sea) are not treated as built-ins; such a package resolves fromnode_modules.MODULE_NOT_FOUNDkeep their code but not their host paths.builtinModulesloads as a built-in.Compiled import rewrite (
route-adapter.ts)require(...).import * as nsand dynamicimport()produce an ES module namespace via__vf_namespace, withdefaultset to the wholemodule.exports(also for__esModulemodules).Promise.resolve().then(...), so failures reject the promise.__vf_interopDefault.$, Unicode letters and\uescapes. String-literal named imports (import { "a-b" as value }) become quoted destructuring keys.import { default as x }gets the same interop asimport x.with { type: "json" }) and dynamic imports with an options argument are rewritten.export * froma CommonJS package fails with a clear error.<,>, U+2028 and U+2029.Docs
New "npm packages" section in
docs/guides/api-routes.md: supported import forms and namespace shape, thenode_modulesrequirement,exports-map limits,.mjsfiles inside CommonJS packages, re-exports, the errors, and when static versus dynamic imports fail.Tests
route CommonJS require (#5471)inloader.test.ts:prependRouteRequirePrologue, imports the handler and callsGET. Cases:import()$binding.defaulton amodule.exports = functionpackageexport *(rejected)__esModulepackage through default, namespace and dynamic importsMODULE_NOT_FOUNDloadHandlerModuleon the bundle path, where a local.cjscallsrequire("node:path").require.resolveof an existing and a missing relative id, a directory with apackage.jsonmain, a module that throws on first evaluation, top-levelthis, anasync_hooksrequire, a blocked relative path, a circular require with reassigned exports, a malformed local manifest, an extensionless native addon, an.mjsfile in a CommonJS package,module.require, a package namedtest, and a malformed installed manifest.chooseRouteHelperPrefix, the renamed shim, a project path containing a helper name, and literal escaping inexternal-import-rewriter.test.ts; string-literal destructuring inloader-helpers.test.ts.Every new test was confirmed to fail with its fix reverted. Existing assertions on the compiled rewrite text were updated for the namespace and lazy dynamic forms.
Ran locally:
src/routing/api/module-loader/,src/transforms/import-rewriter/,src/routing/api/handler.test.tsdeno checkon changed files,deno task lint,deno fmt --check,lint:anti-slop,lint:sanitizer-baselinedocs:public:check, guide validation