TL;DR
When a Node-only CJS package (e.g. wpapi, superagent) lives anywhere in the import graph, vinext dev crashes at startup with a raw Rolldown stack trace and exits the Node process — no hint that the fix is to add the package to optimizeDeps.exclude. With nodejs_compat enabled, these packages would work at runtime in workerd; the only failure is the build-time dep optimizer.
It took us several hours to identify which package was the trigger and find the workaround. A short, named diagnostic from vinext (or an auto-exclude heuristic) would make this trivial.
Versions
- vinext: 0.0.50
- vite: 8.0.13
- rolldown: bundled with Vite 8 (
node_modules/rolldown/...)
- @cloudflare/vite-plugin: 1.37.0
- compatibility_date: 2026-04-21
- compatibility_flags:
["nodejs_compat"]
Symptom
With optimizeDeps.exclude left empty (the natural starting state), running bun run dev:
file:///.../node_modules/vinext/dist/server/socket-error-backstop.js:114
throw err;
^
Error: Error during dependency optimization:
Build failed with 1 error:
[UNRESOLVED_IMPORT] Could not resolve '../..' in node_modules/superagent/lib/node/agent.js
node_modules/superagent/lib/node/agent.js:10:25
10 │ const request = require('../..');
│ ───┬───
│ ╰───── Module not found.
│
│ Help: 'node_modules/superagent/lib/node/agent.js' is imported by the following path:
│ - node_modules/superagent/lib/node/agent.js
│ - node_modules/superagent/lib/node/index.js
│ - node_modules/wpapi/lib/http-transport.js
│ - node_modules/wpapi/wpapi.js
at aggregateBindingErrorsIntoJsError (.../rolldown/dist/shared/error-CkdMJ9ps.mjs:48:18)
at unwrapBindingResult (.../rolldown/dist/shared/error-CkdMJ9ps.mjs:18:128)
at #build (.../rolldown/dist/shared/rolldown-build-BVD3dIdE.mjs:3275:34)
at async Object.build (.../vite/dist/node/chunks/node.js:31729:18)
Node.js v25.2.1
Dev server exits with non-zero status. No HTTP server starts.
Reproduce
Pull any package that uses CJS require('../..') (self-reference to its own package root) into your app graph. The simplest:
// lib/use-wpapi.ts
import WPAPI from 'wpapi';
export const wp = new WPAPI({ endpoint: 'https://example.com/wp-json' });
Then vinext dev — boom.
(superagent itself is enough; wpapi just transitively pulls it in.)
Root cause
Rolldown's dep optimizer doesn't resolve require('../..') inside superagent/lib/node/agent.js. This is a Rolldown limitation, not strictly a vinext bug — but vinext is the framework that surfaces this to users.
Why this matters for a Workers-targeted framework
With compatibility_flags: ["nodejs_compat"] and a recent compat date, node:http, node:https, node:fs, node:net are all 🟢 supported in workerd (docs). So packages like wpapi/superagent would run fine at the edge. The only reason they break is the dev-time dep optimizer — a tooling artefact, not a runtime constraint.
The workaround (optimizeDeps.exclude: ['wpapi', 'superagent']) is one line, but is undiscoverable without:
- Knowing what "dep optimizer" means in Vite-speak
- Recognising that "fix this Rolldown unresolved-import" → "exclude from optimization"
- Reading the import chain in the error to identify which package to exclude
Asks (in order of helpfulness)
1. Friendly diagnostic wrapper. When the dep optimizer fails with UNRESOLVED_IMPORT, vinext catches the error and prints:
[vinext] Dependency optimization failed for "superagent" (pulled in via wpapi).
This is usually a Node-only CJS package that Rolldown's dep-bundler can't pre-build.
At runtime, workerd with nodejs_compat will run it fine.
Fix: add it to optimizeDeps.exclude in vite.config.ts:
optimizeDeps: {
exclude: ['wpapi', 'superagent'],
}
(Both the leaf package and the package that imports it should be listed.)
Even just printing the package names from the import chain + the one-line fix would save users hours.
2. Auto-exclude on Rolldown UNRESOLVED_IMPORT. On the first dep-optimization run, if a package fails with this specific error code, vinext could:
- Auto-exclude it for the current dev session
- Print a message: "Auto-excluding
superagent from optimizeDeps — add this to your vite.config.ts to make it permanent"
3. Bundled known-broken list. Vinext could ship a tiny known-broken-CJS list (wpapi, superagent, anything else commonly hit) and add it to optimizeDeps.exclude by default. Users can opt out.
Even just (1) alone would make the difference between a 10-second fix and a multi-hour debugging session.
Bonus context
We also hit a separate, much more cryptic dep-runtime crash from the same family — Cannot read properties of undefined (reading '__cjs_module_runner_transform') inside @vitejs/plugin-rsc's helper. That one's an upstream plugin-rsc issue (worth its own diagnostic), but the user-facing fix in both cases is the same: add the package to optimizeDeps.exclude. A single well-worded vinext error message could cover both.
TL;DR
When a Node-only CJS package (e.g.
wpapi,superagent) lives anywhere in the import graph,vinext devcrashes at startup with a raw Rolldown stack trace and exits the Node process — no hint that the fix is to add the package tooptimizeDeps.exclude. Withnodejs_compatenabled, these packages would work at runtime in workerd; the only failure is the build-time dep optimizer.It took us several hours to identify which package was the trigger and find the workaround. A short, named diagnostic from vinext (or an auto-exclude heuristic) would make this trivial.
Versions
node_modules/rolldown/...)["nodejs_compat"]Symptom
With
optimizeDeps.excludeleft empty (the natural starting state), runningbun run dev:Dev server exits with non-zero status. No HTTP server starts.
Reproduce
Pull any package that uses CJS
require('../..')(self-reference to its own package root) into your app graph. The simplest:Then
vinext dev— boom.(
superagentitself is enough;wpapijust transitively pulls it in.)Root cause
Rolldown's dep optimizer doesn't resolve
require('../..')insidesuperagent/lib/node/agent.js. This is a Rolldown limitation, not strictly a vinext bug — but vinext is the framework that surfaces this to users.Why this matters for a Workers-targeted framework
With
compatibility_flags: ["nodejs_compat"]and a recent compat date,node:http,node:https,node:fs,node:netare all 🟢 supported in workerd (docs). So packages likewpapi/superagentwould run fine at the edge. The only reason they break is the dev-time dep optimizer — a tooling artefact, not a runtime constraint.The workaround (
optimizeDeps.exclude: ['wpapi', 'superagent']) is one line, but is undiscoverable without:Asks (in order of helpfulness)
1. Friendly diagnostic wrapper. When the dep optimizer fails with
UNRESOLVED_IMPORT, vinext catches the error and prints:Even just printing the package names from the import chain + the one-line fix would save users hours.
2. Auto-exclude on Rolldown UNRESOLVED_IMPORT. On the first dep-optimization run, if a package fails with this specific error code, vinext could:
superagentfrom optimizeDeps — add this to your vite.config.ts to make it permanent"3. Bundled known-broken list. Vinext could ship a tiny known-broken-CJS list (
wpapi,superagent, anything else commonly hit) and add it tooptimizeDeps.excludeby default. Users can opt out.Even just (1) alone would make the difference between a 10-second fix and a multi-hour debugging session.
Bonus context
We also hit a separate, much more cryptic dep-runtime crash from the same family —
Cannot read properties of undefined (reading '__cjs_module_runner_transform')inside@vitejs/plugin-rsc's helper. That one's an upstream plugin-rsc issue (worth its own diagnostic), but the user-facing fix in both cases is the same: add the package tooptimizeDeps.exclude. A single well-worded vinext error message could cover both.