[GH-ISSUE #407] feat: add create-vinext-app scaffolding CLI #88

Open
opened 2026-05-06 12:37:08 +02:00 by BreizhHardware · 1 comment

Originally created by @Divkix on GitHub (Mar 10, 2026).
Original GitHub issue: https://github.com/cloudflare/vinext/issues/407

What

A standalone CLI package — packages/create-vinext-app/ — that scaffolds a working vinext project with one command, no manual steps. npm create vinext-app@latest my-app --yes should Just Work.
Right now the only path is npm create next-app@latestvinext init → manually create wrangler.jsonc and a worker entry. It's 8-12 steps for something that should be one.

Why

vinext init is good for migrating existing Next.js projects. It's the wrong tool for starting from scratch. A fresh project shouldn't need Next.js installed to get bootstrapped.
The README currently says create-next-app scaffolding is "Not a goal" — that line should be removed. This makes it a goal.

What's needed

CLI package (packages/create-vinext-app/)

Node >= 18. Pure ESM ("type": "module"). No framework dependencies beyond @clack/prompts.

  • index.ts — argument parsing, help text, wiring
  • validate.ts — project name validation (npm rules plus extra constraints), empty directory check
  • prompts.ts — interactive project name + template selection, cancel-safe
  • scaffold.ts — copy template, substitute .tmpl variables, rename _gitignore, optional git init + npm install
  • install.ts — package manager detection from npm_config_user_agent
    Flags: --template app|pages, --yes, --skip-install, --no-git, --help, --version.

Two templates

App Router:

  • Deps: vinext, @vitejs/plugin-rsc, react-server-dom-webpack, react, react-dom, @vitejs/plugin-react
  • DevDeps: vite, wrangler, @cloudflare/vite-plugin, @cloudflare/workers-types, typescript, vite-plus
  • Scripts: "dev": "vp dev", "build": "vp build", "preview": "vp preview"
  • vite.config.ts: vinext() + cloudflare({ viteEnvironment: { name: "rsc", childEnvironments: ["ssr"] } })
  • wrangler.jsonc: main: "vinext/server/app-router-entry", assets binding
  • Sample app with layout, page, and API route
    Pages Router:
  • Deps: vinext, react, react-dom, @vitejs/plugin-react
  • DevDeps: same as App Router
  • Scripts: "dev": "vp dev", "build": "vp build", "preview": "vp preview"
  • vite.config.ts: vinext() + cloudflare()
  • wrangler.jsonc: main: "./worker/index.ts"
  • A custom worker entry (worker/index.ts) handling middleware, config redirects/rewrites/headers, API routing, and SSR. Config redirects need to run before middleware (this was wrong in the initial PR — redirects ran after).
  • Sample pages: index, about, and API route
    The pages-router worker entry is ~200 lines copied from examples/pages-router-cloudflare/worker/index.ts. Eventually this should be extracted into vinext/server/pages-router-entry so templates can reference it instead of duplicating code. The initial PR had a TODO for this. Not a launch blocker but it'll cause drift if left too long — every fix to the example worker entry needs to be manually ported to the template.

Template variables

.tmpl files get {{PROJECT_NAME}}, {{WORKER_NAME}} (sanitized: lowercase, alphanumeric + hyphens), and {{VINEXT_VERSION}} (set to the CLI's own version, since the publish workflow syncs both packages).
_gitignore gets renamed to .gitignore.

CI

A job that scaffolds a project with --yes --skip-install, installs deps (including a local vinext tarball from the build step), starts the dev server, and curls for HTTP 200. Needs to run on ubuntu + windows for both templates.
The job should integrate into the restructured CI (unified check, sharded test-integration) rather than the old per-step layout.

Publish

Version-bump create-vinext-app alongside vinext and publish both in the same workflow run. Uses OIDC trusted publishing. Already wired up in the publish workflow on the feature branch — needs to be rebased onto current main.

README

Replace the "Starting a new vinext project" section (which currently says to use npm create next-app@latest) with npm create vinext-app@latest. Remove the "Not a goal" line about create-next-app scaffolding. Update the migration skill's compatibility docs if needed.

Prior art

PR #406 has a working implementation on branch feat/create-vinext-app. Most of the code is written and has gone through two rounds of review. It needs rebasing onto current main and the templates updated for the repo changes since March (Vite 8, vite-plus, CI restructuring, worker entry fixes). Will be creating a new PR for that as we need to update and match new state of code.

Acceptance criteria

  • npm create vinext-app@latest my-app --yes scaffolds a working project (both templates)
  • vp dev responds with HTTP 200 in the scaffolded project
  • vp build succeeds (compiles RSC + SSR + client for App Router, SSR for Pages Router)
  • CLI handles bare names, scoped names (@org/app), relative paths, absolute paths, and . (current dir)
  • All tests pass (unit, integration, scaffolding, CLI, templates)
  • CI scaffolds and validates both templates on ubuntu and windows
  • Publish workflow ships both vinext and create-vinext-app together
  • README updated, "Not a goal" line removed

Update: Edited on May 2, 2026 to match current state on the date

Originally created by @Divkix on GitHub (Mar 10, 2026). Original GitHub issue: https://github.com/cloudflare/vinext/issues/407 ## What A standalone CLI package — `packages/create-vinext-app/` — that scaffolds a working vinext project with one command, no manual steps. `npm create vinext-app@latest my-app --yes` should Just Work. Right now the only path is `npm create next-app@latest` → `vinext init` → manually create `wrangler.jsonc` and a worker entry. It's 8-12 steps for something that should be one. ## Why `vinext init` is good for migrating existing Next.js projects. It's the wrong tool for starting from scratch. A fresh project shouldn't need Next.js installed to get bootstrapped. The README currently says `create-next-app` scaffolding is "Not a goal" — that line should be removed. This makes it a goal. ## What's needed ### CLI package (`packages/create-vinext-app/`) Node >= 18. Pure ESM (`"type": "module"`). No framework dependencies beyond `@clack/prompts`. - `index.ts` — argument parsing, help text, wiring - `validate.ts` — project name validation (npm rules plus extra constraints), empty directory check - `prompts.ts` — interactive project name + template selection, cancel-safe - `scaffold.ts` — copy template, substitute `.tmpl` variables, rename `_gitignore`, optional `git init` + `npm install` - `install.ts` — package manager detection from `npm_config_user_agent` Flags: `--template app|pages`, `--yes`, `--skip-install`, `--no-git`, `--help`, `--version`. ### Two templates **App Router:** - Deps: `vinext`, `@vitejs/plugin-rsc`, `react-server-dom-webpack`, `react`, `react-dom`, `@vitejs/plugin-react` - DevDeps: `vite`, `wrangler`, `@cloudflare/vite-plugin`, `@cloudflare/workers-types`, `typescript`, `vite-plus` - Scripts: `"dev": "vp dev"`, `"build": "vp build"`, `"preview": "vp preview"` - `vite.config.ts`: `vinext()` + `cloudflare({ viteEnvironment: { name: "rsc", childEnvironments: ["ssr"] } })` - `wrangler.jsonc`: `main: "vinext/server/app-router-entry"`, assets binding - Sample app with layout, page, and API route **Pages Router:** - Deps: `vinext`, `react`, `react-dom`, `@vitejs/plugin-react` - DevDeps: same as App Router - Scripts: `"dev": "vp dev"`, `"build": "vp build"`, `"preview": "vp preview"` - `vite.config.ts`: `vinext()` + `cloudflare()` - `wrangler.jsonc`: `main: "./worker/index.ts"` - A custom worker entry (`worker/index.ts`) handling middleware, config redirects/rewrites/headers, API routing, and SSR. Config redirects need to run *before* middleware (this was wrong in the initial PR — redirects ran after). - Sample pages: index, about, and API route The pages-router worker entry is ~200 lines copied from `examples/pages-router-cloudflare/worker/index.ts`. Eventually this should be extracted into `vinext/server/pages-router-entry` so templates can reference it instead of duplicating code. The initial PR had a TODO for this. Not a launch blocker but it'll cause drift if left too long — every fix to the example worker entry needs to be manually ported to the template. ### Template variables `.tmpl` files get `{{PROJECT_NAME}}`, `{{WORKER_NAME}}` (sanitized: lowercase, alphanumeric + hyphens), and `{{VINEXT_VERSION}}` (set to the CLI's own version, since the publish workflow syncs both packages). `_gitignore` gets renamed to `.gitignore`. ### CI A job that scaffolds a project with `--yes --skip-install`, installs deps (including a local vinext tarball from the build step), starts the dev server, and curls for HTTP 200. Needs to run on ubuntu + windows for both templates. The job should integrate into the restructured CI (unified `check`, sharded `test-integration`) rather than the old per-step layout. ### Publish Version-bump `create-vinext-app` alongside vinext and publish both in the same workflow run. Uses OIDC trusted publishing. Already wired up in the publish workflow on the feature branch — needs to be rebased onto current main. ### README Replace the "Starting a new vinext project" section (which currently says to use `npm create next-app@latest`) with `npm create vinext-app@latest`. Remove the "Not a goal" line about `create-next-app` scaffolding. Update the migration skill's compatibility docs if needed. ## Prior art PR #406 has a working implementation on branch `feat/create-vinext-app`. Most of the code is written and has gone through two rounds of review. It needs rebasing onto current main and the templates updated for the repo changes since March (Vite 8, vite-plus, CI restructuring, worker entry fixes). Will be creating a new PR for that as we need to update and match new state of code. ## Acceptance criteria - [ ] `npm create vinext-app@latest my-app --yes` scaffolds a working project (both templates) - [ ] `vp dev` responds with HTTP 200 in the scaffolded project - [ ] `vp build` succeeds (compiles RSC + SSR + client for App Router, SSR for Pages Router) - [ ] CLI handles bare names, scoped names (`@org/app`), relative paths, absolute paths, and `.` (current dir) - [ ] All tests pass (unit, integration, scaffolding, CLI, templates) - [ ] CI scaffolds and validates both templates on ubuntu and windows - [ ] Publish workflow ships both vinext and create-vinext-app together - [ ] README updated, "Not a goal" line removed Update: Edited on May 2, 2026 to match current state on the date
Author
Owner

@james-elicx commented on GitHub (Mar 10, 2026):

N.B. I've claimed the package name for now - can transfer ownership later if needed.

I would agree that it's reasonable for vinext to have it's own create-vinext-app package separate to create-cloudflare, given that non-cloudflare builds are supported. That and aligning with what Next.js has. (happy to be challenged on that though!)

<!-- gh-comment-id:4030380280 --> @james-elicx commented on GitHub (Mar 10, 2026): N.B. I've claimed the package name for now - can transfer ownership later if needed. I would agree that it's reasonable for vinext to have it's own create-vinext-app package separate to create-cloudflare, given that non-cloudflare builds are supported. That and aligning with what Next.js has. (happy to be challenged on that though!)
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#88
No description provided.