You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Several webjs CLI commands hard-code a runtime/tool that only exists under Node, so they break under Bun (and in a Node-less oven/bun image):
webjs db <generate|migrate|push|studio> shells npx drizzle-kit. A pure oven/bun image has no npx (it ships only a node fallback shim), so webjs db migrate fails at container boot.
webjs test --server spawns process.execPath --test. Under Bun that becomes bun --test, which is invalid (Bun's runner is the bun test subcommand; bun --test errors with "Cannot use test outside of the test runner").
webjs test --browser shells npx wtr (same npx-absent problem under Bun).
This forced #541 (Bun-first scaffold) to keep a node:24-alpine base and copy the Bun binary into the image, instead of a clean FROM oven/bun:1. Making the commands runtime-native removes that workaround and lets a bun scaffold ship a pure oven/bun Dockerfile.
Design / approach
The codebase already has the pattern: webjs typecheck resolves the app's own tsc via createRequire(join(process.cwd(), 'package.json')) and spawns it with process.execPath (so it runs under whatever runtime is current, Node or Bun). Apply the same to the other commands:
webjs db: resolve the drizzle-kit bin via createRequire from the app cwd and spawn it with process.execPath (no npx/bunx). Verified: bun <drizzle-kit-bin> --version runs cleanly (drizzle-kit v1.0.0-rc.3), so drizzle-kit works under Bun.
webjs test --browser: resolve the wtr (@web/test-runner) bin the same way and spawn with process.execPath (drop npx wtr). (wtr-under-bun should be verified; if it does not run under Bun, gate this one to keep node for the browser layer and document it.)
webjs test --server: this is the hard one. node --test and bun test are different runners with different flag shapes and partially different node:test semantics. Detect the runtime (process.versions.bun) and dispatch: node --test <files> on Node, bun test <files> on Bun. Verify the scaffold's example node:test-style tests pass under bun test (the repo's own bun matrix already runs node:test files under bun test, so this is plausible), and reconcile the e2e gating (WEBJS_E2E) + the wtr browser layer.
Scope can land incrementally: the webjs db fix alone makes a pure oven/bunDockerfile viable (the container only runs start -> start.before -> webjs db migrate, never tests). The webjs test fixes are what make a fully Node-free CI possible.
Implementation notes (for the implementing agent)
Where to edit, all in packages/cli/bin/webjs.js:
webjs db case: spawn('npx', ['drizzle-kit', ...kitArgs, ...args], ...) at L221. Replace with a resolved-bin + process.execPath spawn.
webjs test --server: spawn(process.execPath, ['--test', ...testFiles], ...) at L301. Branch on process.versions.bun: bun test vs node --test.
webjs test --browser: spawn('npx', ['wtr'], ...) at L314 and spawn('npx', ['wtr', '--files', ...], ...) at L324. Resolve the wtr bin.
Prior art to copy: the webjs typecheck case (L443-L455) resolves tsc via createRequire(join(process.cwd(), 'package.json')) and spawns process.execPath, [tscPath, ...]. webjs db seed (L211) already spawns process.execPath, [seedFile]. Mirror these.
Landmines:
bun --test is NOT bun test (the flag form is invalid). Use the subcommand form.
oven/bun has a node shim at /usr/local/bun-node-fallback-bin/node but NO npx/bunx-as-npx. Do not rely on npx.
Resolving the bin from the app cwd (not import.meta.url) matters: the bin must come from the APP's node_modules (drizzle-kit / wtr are the app's devDependencies), like webjs typecheck resolves the app's tsc.
drizzle-kit's entry is drizzle-kit/bin.cjs (a .cjs); confirm the resolve target.
Invariants: packages/ stays plain .js + JSDoc (no .ts). Keep the commands' Node behaviour byte-identical (this must not regress Node users).
Tests + docs: packages/cli/test/ for the dispatch logic (unit, with an injectable spawn); a Bun cross-runtime assert if feasible. Run the 4 dogfood apps' webjs db generate/migrate on BOTH runtimes. Docs: packages/cli/AGENTS.md (the command table), agent-docs/testing.md if the test-runner behaviour changes, and the deployment docs (the pure-oven/bun Dockerfile becomes possible).
Acceptance criteria
webjs db generate / migrate / push run with NO npx dependency, on both Node and Bun, including in a Node-less oven/bun image.
webjs test --server runs the suite on both runtimes (node --test on Node, bun test on Bun), with the e2e gating preserved.
webjs test --browser resolves wtr without npx (or, if wtr cannot run under Bun, is explicitly gated to Node with a documented reason).
Node behaviour is unchanged (a counterfactual / existing tests prove no Node regression).
The 4 in-repo apps' db commands work on both runtimes.
Problem
Several
webjsCLI commands hard-code a runtime/tool that only exists under Node, so they break under Bun (and in a Node-lessoven/bunimage):webjs db <generate|migrate|push|studio>shellsnpx drizzle-kit. A pureoven/bunimage has nonpx(it ships only anodefallback shim), sowebjs db migratefails at container boot.webjs test --serverspawnsprocess.execPath --test. Under Bun that becomesbun --test, which is invalid (Bun's runner is thebun testsubcommand;bun --testerrors with "Cannot use test outside of the test runner").webjs test --browsershellsnpx wtr(samenpx-absent problem under Bun).This forced #541 (Bun-first scaffold) to keep a
node:24-alpinebase and copy the Bun binary into the image, instead of a cleanFROM oven/bun:1. Making the commands runtime-native removes that workaround and lets a bun scaffold ship a pureoven/bunDockerfile.Design / approach
The codebase already has the pattern:
webjs typecheckresolves the app's owntscviacreateRequire(join(process.cwd(), 'package.json'))and spawns it withprocess.execPath(so it runs under whatever runtime is current, Node or Bun). Apply the same to the other commands:webjs db: resolve thedrizzle-kitbin viacreateRequirefrom the app cwd and spawn it withprocess.execPath(nonpx/bunx). Verified:bun <drizzle-kit-bin> --versionruns cleanly (drizzle-kit v1.0.0-rc.3), so drizzle-kit works under Bun.webjs test --browser: resolve thewtr(@web/test-runner) bin the same way and spawn withprocess.execPath(dropnpx wtr). (wtr-under-bun should be verified; if it does not run under Bun, gate this one to keepnodefor the browser layer and document it.)webjs test --server: this is the hard one.node --testandbun testare different runners with different flag shapes and partially differentnode:testsemantics. Detect the runtime (process.versions.bun) and dispatch:node --test <files>on Node,bun test <files>on Bun. Verify the scaffold's examplenode:test-style tests pass underbun test(the repo's own bun matrix already runsnode:testfiles underbun test, so this is plausible), and reconcile the e2e gating (WEBJS_E2E) + the wtr browser layer.Scope can land incrementally: the
webjs dbfix alone makes a pureoven/bunDockerfile viable (the container only runsstart->start.before->webjs db migrate, never tests). Thewebjs testfixes are what make a fully Node-free CI possible.Implementation notes (for the implementing agent)
packages/cli/bin/webjs.js:webjs dbcase:spawn('npx', ['drizzle-kit', ...kitArgs, ...args], ...)at L221. Replace with a resolved-bin +process.execPathspawn.webjs test --server:spawn(process.execPath, ['--test', ...testFiles], ...)at L301. Branch onprocess.versions.bun:bun testvsnode --test.webjs test --browser:spawn('npx', ['wtr'], ...)at L314 andspawn('npx', ['wtr', '--files', ...], ...)at L324. Resolve the wtr bin.webjs typecheckcase (L443-L455) resolvestscviacreateRequire(join(process.cwd(), 'package.json'))and spawnsprocess.execPath, [tscPath, ...].webjs db seed(L211) already spawnsprocess.execPath, [seedFile]. Mirror these.bun --testis NOTbun test(the flag form is invalid). Use the subcommand form.oven/bunhas anodeshim at/usr/local/bun-node-fallback-bin/nodebut NOnpx/bunx-as-npx. Do not rely onnpx.import.meta.url) matters: the bin must come from the APP's node_modules (drizzle-kit / wtr are the app's devDependencies), likewebjs typecheckresolves the app's tsc.drizzle-kit/bin.cjs(a .cjs); confirm the resolve target.packages/stays plain.js+ JSDoc (no.ts). Keep the commands' Node behaviour byte-identical (this must not regress Node users).packages/cli/test/for the dispatch logic (unit, with an injectable spawn); a Bun cross-runtime assert if feasible. Run the 4 dogfood apps'webjs db generate/migrateon BOTH runtimes. Docs:packages/cli/AGENTS.md(the command table),agent-docs/testing.mdif the test-runner behaviour changes, and the deployment docs (the pure-oven/bunDockerfile becomes possible).Acceptance criteria
webjs db generate/migrate/pushrun with NOnpxdependency, on both Node and Bun, including in a Node-lessoven/bunimage.webjs test --serverruns the suite on both runtimes (node --teston Node,bun teston Bun), with the e2e gating preserved.webjs test --browserresolves wtr withoutnpx(or, if wtr cannot run under Bun, is explicitly gated to Node with a documented reason).FROM oven/bun:1(follow-up on that PR).packages/cli/AGENTS.md, deployment docs, testing docs.