feat: Bun-first scaffold mode (--runtime bun) across all 3 templates#569
Merged
Conversation
vivek7405
pushed a commit
that referenced
this pull request
Jun 18, 2026
…pper arg parse) Self-review findings on #569: - The generated bun AGENTS.md 'Running on Bun' section framed Bun as opt-in ('force it with --bun'), but the bun app's dev/start scripts already embed --bun. Reframe it as the configured default. - bunifyCi left the e2e Chromium-path step on 'node -e'; switch it to 'bun -e' so a fully-Bun CI does not rely on Node being implicitly present. - create-webjs positional parsing read a value-taking flag's value as the app name (e.g. 'create-webjs --runtime bun my-app' picked 'bun'); skip flag values when collecting positionals.
vivek7405
pushed a commit
that referenced
this pull request
Jun 18, 2026
Round-2 review findings on #569: - The scaffolded starter tests (test/hello/browser, test/hello/e2e) carried 'npx wtr' / 'npm i -D puppeteer-core' header comments copied verbatim, so a bun app shipped test files telling the user to run npm/npx. Add them to the prose-rewrite set and teach bunifyProse the 'npm i' shorthand. - create-webjs forwarded template/runtime/install but dropped --db, so 'bun create webjs my-app --db postgres' silently scaffolded sqlite while the docstring claimed behaviour matches 'webjs create' exactly. Forward --db (and skip its value in positional parsing).
Collaborator
Author
|
Self-review: 5 rounds, last clean Ran fresh-context review rounds over the whole change. What they caught and how it was resolved:
Generated output verified for both runtimes and all three templates, |
added 11 commits
June 18, 2026 13:14
…rites) Add a runtime axis orthogonal to --template (the 3-templates invariant is untouched). `webjs create --runtime bun` (and `bun create webjs`, auto-detected from the invoking PM) emits a Bun-flavored app: - package.json: dev/start scripts force `bun --bun webjs ...` so the long-running server runs on Bun despite the webjs bin's node shebang (the gotcha); tooling scripts stay plain webjs (node:test/drizzle-kit/tsc are runtime-neutral). trustedDependencies=[better-sqlite3] so its native prebuild postinstall runs (Bun skips postinstalls by default). - bun install (commits bun.lock) instead of npm/package-lock. - Dockerfile -> oven/bun:1 base + bun install + bun -e healthcheck + bun start; compose healthcheck -> bun -e; CI -> setup-bun + bun install + bun --bun run. - agent-config markdown -> bun command forms. All derived from the canonical node templates by pure transforms (runtime-rewrite.js) so there is no parallel bun template to drift. Node mode is byte-identical to before. Tests + docs follow in subsequent commits.
templates/.cursorrules still described Prisma (prisma/schema.prisma, lib/prisma.server.ts, @prisma/client, 'define a Prisma model'), missed in the #558 Prisma->Drizzle migration while the sibling agent configs were updated. Sync it to Drizzle (db/schema.server.ts, db/connection.server.ts, db:generate + db:migrate, better-sqlite3/pg driver). Also extend bunifyProse so the bun-mode AGENTS.md Dockerfile prose matches the generated bun Dockerfile (node:24-alpine -> oven/bun:1 pin claim, and the CMD [npm start] -> CMD [bun --bun run start] equivalence note).
Unit tests for the pure bunify* transforms (commands, registry-noun survival, Dockerfile/compose/CI rewrites) and integration tests asserting a bun scaffold across all 3 templates: dev/start force --bun, trustedDependencies is sqlite-only, the deploy/CI files run on Bun, the agent markdown carries no npm commands, bun is auto-detected from the invoking PM, the explicit flag overrides detection, an unknown runtime is rejected, and node mode stays byte-unchanged.
…d, deployment) packages/cli/AGENTS.md: runtime-rewrite.js module-map entry, the create command row, and an invariant-1 note that --runtime is orthogonal (not a 4th template). Root AGENTS.md scaffolding section: the --runtime flag. Docs site: a getting-started Bun-scaffold subsection (both bun create / bunx create-webjs invocation styles + the npm -- separator note) and a deployment bullet for the generated pure oven/bun Dockerfile.
…pper arg parse) Self-review findings on #569: - The generated bun AGENTS.md 'Running on Bun' section framed Bun as opt-in ('force it with --bun'), but the bun app's dev/start scripts already embed --bun. Reframe it as the configured default. - bunifyCi left the e2e Chromium-path step on 'node -e'; switch it to 'bun -e' so a fully-Bun CI does not rely on Node being implicitly present. - create-webjs positional parsing read a value-taking flag's value as the app name (e.g. 'create-webjs --runtime bun my-app' picked 'bun'); skip flag values when collecting positionals.
Round-2 review findings on #569: - The scaffolded starter tests (test/hello/browser, test/hello/e2e) carried 'npx wtr' / 'npm i -D puppeteer-core' header comments copied verbatim, so a bun app shipped test files telling the user to run npm/npx. Add them to the prose-rewrite set and teach bunifyProse the 'npm i' shorthand. - create-webjs forwarded template/runtime/install but dropped --db, so 'bun create webjs my-app --db postgres' silently scaffolded sqlite while the docstring claimed behaviour matches 'webjs create' exactly. Forward --db (and skip its value in positional parsing).
Round-3 review exposed two correctness bugs in the bun runtime design, both verified empirically: 1. webjs test spawns process.execPath --test. Under bun that is 'bun --test', which is INVALID (bun's runner is 'bun test'; 'bun --test' errors). So forcing --bun on the test scripts (bunifyCi did 'bun --bun run test:server') would fail CI. Fix: only the SERVER scripts (dev/start) force --bun; all tooling (test/db/check/typecheck) stays on Node via plain 'bun run' / the webjs bin's node shebang. bunifyProse and bunifyCi updated accordingly. 2. webjs db migrate shells 'npx drizzle-kit', and a pure oven/bun image has no npx (confirmed: oven/bun ships a node fallback shim but no npx). So a pure oven/bun Dockerfile base breaks migrate-at-boot. Fix: the bun Dockerfile KEEPS the node:24-alpine base and COPIES in the bun binary (npx + node toolchain present, server serves on bun via 'bun --bun run start'), the verified pattern the in-repo apps use. compose.yaml no longer needs a transform (inherits the Dockerfile CMD; its node -e healthcheck works on the node base). Docs (root + cli AGENTS, getting-started, deployment) corrected to describe the node-base+bun-binary Dockerfile and the node-tooling split. Tests updated.
…--bun run) The comment claimed the bun-ified auth-test reads 'bun --bun run db:*'; the actual (correct) output is plain 'bun run db:*' since db is Node tooling. The generated output was already right; only the code comment was wrong.
The --runtime USAGE line used backticks around 'bun create webjs' inside the backtick-delimited USAGE template literal, which closed it and made bin/webjs.js a SyntaxError (the CLI would not load). Tests missed it because they import lib/create.js, not the bin. Use double quotes instead. Verified with node --check + running the bin.
…default) test/preload-subset.test.mjs boots all four in-repo apps and probes their modulepreloads (#204); the website boot's jspm vendor resolution tips just over bun test's 5s per-test default on the CI runner (~5.1s locally). Same app-boot + vendor-resolution class as the already-denylisted differential-elision and test/docs. The invariant is covered on the Node path; a real bun app boot is covered by test/bun/listener.mjs. Pre-existing flake (#204), surfaced on the #541 PR's bun matrix; unrelated to the scaffold change.
…ebase After rebasing on #570 (npx-free webjs db/test), a pure oven/bun scaffold Dockerfile is technically viable, but scaffolds pin @webjsdev/cli: latest, so it is only safe once cli with #570 is PUBLISHED (an old installed cli still shells npx, which a pure oven/bun image lacks). So #541 ships the node-base + bun-binary Dockerfile (works with any cli version); align the cli AGENTS and deployment docs to that, noting a pure oven/bun image becomes the default in a future scaffold once cli@#570 is the published latest.
b209bdc to
3cb7315
Compare
Post-#570, webjs db migrate is npx-free, so the old justification ('keep the node base because webjs db migrate needs npx') is stale and was a same-file self-contradiction in packages/cli/AGENTS.md (the runtime-rewrite entry vs the #570 webjs db row), plus it shipped into every generated bun Dockerfile comment. The real reason the scaffold stays node-base: a scaffolded app pins @webjsdev/cli: latest, and until the npx-free #570 build is the published latest, an installed CLI may still shell npx for the boot webjs db migrate, which a pure oven/bun image lacks. The node base works with ANY installed CLI; a future scaffold can drop to a pure oven/bun base once #570 is published. Rewrote the rationale in runtime-rewrite.js (incl. the baked Dockerfile comment), packages/cli/AGENTS.md, root AGENTS.md, and getting-started.
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.
Closes #541
Adds a
--runtime node|bunaxis towebjs create, ORTHOGONAL to--template(the exactly-3-templates invariant is untouched).--runtime bun, andbun create webjs <name>(auto-detected from the invoking package manager), emit a Bun-flavored app across all three templates;--runtime node(the default) is byte-identical to today.The load-bearing design decision: server on Bun, tooling on Node
The SERVER (the
dev/startscripts) runs on Bun, because that is the app. The dev/build TOOLING (webjs test/db:*/check/typecheck) stays on Node, because two things break under Bun (both verified empirically):webjs testspawnsnode --test; under Bun that becomesbun --test, which is invalid (Bun's runner isbun test).webjs db migrateshellsnpx drizzle-kit, and a pureoven/bunimage has nonpx.So: only
dev/startforcebun --bun(overriding thewebjsbin's Node shebang); everything else stays plainwebjs/bun runon Node.What bun mode changes in the generated app
dev/startbecomebun --bun webjs ...; tooling stays plainwebjs ....["better-sqlite3"](sqlite only) so its native-prebuild postinstall runs (Bun skips postinstalls). Pure-JSpgneeds none.bun installwritesbun.lock.node:24-alpinebase and COPIES in the Bun binary (sonpx/ drizzle-kit / the shebang bins work AND the server serves on Bun viaCMD ["bun","--bun","run","start"]). A pureoven/bunbase is deliberately NOT used (nonpx).bun install,bun.lock,node -ehealthcheck (the node base provides node).actions/setup-node(the tooling runs on node), ADDSoven-sh/setup-bun, installs withbun install, runs scripts with plainbun run.node -ehealthcheck works on the node base).All bun output is DERIVED from the canonical node templates by pure string transforms (
packages/cli/lib/runtime-rewrite.js), so there is no parallel bun template to drift.Drive-by
Fixed stale Prisma references in
templates/.cursorrules(missed in the #558 Prisma->Drizzle migration while the sibling agent configs were updated).Note on the issue body
The issue predates the #558 Drizzle migration, so its Prisma references are adapted to Drizzle (
trustedDependenciescoversbetter-sqlite3, not the Prisma client). There is no README template to bun-ify (the scaffold generates none).Tests + verification
packages/cli/test/runtime-rewrite/(unit, the pure transforms) +test/scaffolds/scaffold-runtime.test.js(integration across all 3 templates, autodetect, override, node-unchanged, unknown-runtime rejection). Full CLI + scaffold suites: 40 pass.webjs checkwith only the 2 expected scaffold-placeholder violations (no transform-introduced violations); node and bun produce identical check output.@webjsdev/core/server, not the cli create logic). Node-mode scaffold output is byte-identical to before.Docs surfaces
AGENTS.md(scaffolding section),packages/cli/AGENTS.md(module map + create row + invariant-1 orthogonality note),bin/webjs.jsUSAGE, docs sitegetting-started(bothbun create webjs/bunx create-webjs@latestinvocation styles + the npm--separator note) anddeployment(the generated node-base+bun-binary Dockerfile).website/app/page.ts(makes no claim contradicted by this change;npm create webjsstays the canonical hero command and bun is auto-detected); MCP / editor plugins (no introspection surface or grammar changed); other docs topics.Self-review
Ran the self-review loop to a clean round. Findings fixed along the way: the generated Bun-section doc framing, CI
bun -e(later reverted with the node-base correction), thecreate-webjsarg parser reading a flag value as the app name, starter-test-comment bun-ification +npm ishorthand,--dbforwarding through the wrapper, the server-on-bun/tooling-on-node correction (thebun --test+ missing-npxdiscoveries), a saas-template comment, and a USAGE template-literal syntax bug.