create-lumen 2.0.0-alpha.2 → 2.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -6
- package/bin/cli.js +2 -1
- package/package.json +2 -2
- package/src/cli-args.js +105 -5
- package/src/configure.js +8 -4
- package/src/dependencies.js +8 -2
- package/src/engine/capabilities.js +22 -1
- package/src/engine/composition.js +92 -0
- package/src/engine/providers/base-provider.js +4 -4
- package/src/main.js +33 -10
- package/src/manifest/emit.js +1 -1
- package/src/prompts.js +154 -23
- package/templates/bases/next/app-router/js/.provenance.json +19 -0
- package/templates/bases/next/app-router/js/README.md +36 -0
- package/templates/bases/next/app-router/js/jsconfig.json +7 -0
- package/templates/bases/next/app-router/js/next.config.mjs +6 -0
- package/templates/bases/next/app-router/js/package.json +15 -0
- package/templates/bases/next/app-router/js/public/file.svg +1 -0
- package/templates/bases/next/app-router/js/public/globe.svg +1 -0
- package/templates/bases/next/app-router/js/public/next.svg +1 -0
- package/templates/bases/next/app-router/js/public/vercel.svg +1 -0
- package/templates/bases/next/app-router/js/public/window.svg +1 -0
- package/templates/bases/next/app-router/js/src/app/api/hello/route.js +5 -0
- package/templates/bases/next/app-router/js/src/app/blog/[slug]/page.js +33 -0
- package/templates/bases/next/app-router/js/src/app/favicon.ico +0 -0
- package/templates/bases/next/app-router/js/src/app/globals.css +49 -0
- package/templates/bases/next/app-router/js/src/app/layout.js +25 -0
- package/templates/bases/next/app-router/js/src/app/loading.js +15 -0
- package/templates/bases/next/app-router/js/src/app/not-found.js +29 -0
- package/templates/bases/next/app-router/js/src/app/page.js +69 -0
- package/templates/bases/next/app-router/js/src/app/page.module.css +150 -0
- package/templates/bases/next/app-router/ts/.provenance.json +19 -0
- package/templates/bases/next/app-router/ts/README.md +36 -0
- package/templates/bases/next/app-router/ts/next.config.ts +7 -0
- package/templates/bases/next/app-router/ts/package.json +21 -0
- package/templates/bases/next/app-router/ts/public/file.svg +1 -0
- package/templates/bases/next/app-router/ts/public/globe.svg +1 -0
- package/templates/bases/next/app-router/ts/public/next.svg +1 -0
- package/templates/bases/next/app-router/ts/public/vercel.svg +1 -0
- package/templates/bases/next/app-router/ts/public/window.svg +1 -0
- package/templates/bases/next/app-router/ts/src/app/api/hello/route.ts +5 -0
- package/templates/bases/next/app-router/ts/src/app/blog/[slug]/page.tsx +38 -0
- package/templates/bases/next/app-router/ts/src/app/favicon.ico +0 -0
- package/templates/bases/next/app-router/ts/src/app/globals.css +49 -0
- package/templates/bases/next/app-router/ts/src/app/layout.tsx +30 -0
- package/templates/bases/next/app-router/ts/src/app/loading.tsx +15 -0
- package/templates/bases/next/app-router/ts/src/app/not-found.tsx +29 -0
- package/templates/bases/next/app-router/ts/src/app/page.module.css +150 -0
- package/templates/bases/next/app-router/ts/src/app/page.tsx +69 -0
- package/templates/bases/next/app-router/ts/tsconfig.json +34 -0
- package/templates/bases/next/pages-router/js/.provenance.json +19 -0
- package/templates/bases/next/pages-router/js/README.md +40 -0
- package/templates/bases/next/pages-router/js/jsconfig.json +7 -0
- package/templates/bases/next/pages-router/js/next.config.mjs +7 -0
- package/templates/bases/next/pages-router/js/package.json +15 -0
- package/templates/bases/next/pages-router/js/public/favicon.ico +0 -0
- package/templates/bases/next/pages-router/js/public/file.svg +1 -0
- package/templates/bases/next/pages-router/js/public/globe.svg +1 -0
- package/templates/bases/next/pages-router/js/public/next.svg +1 -0
- package/templates/bases/next/pages-router/js/public/vercel.svg +1 -0
- package/templates/bases/next/pages-router/js/public/window.svg +1 -0
- package/templates/bases/next/pages-router/js/src/pages/404.js +35 -0
- package/templates/bases/next/pages-router/js/src/pages/500.js +35 -0
- package/templates/bases/next/pages-router/js/src/pages/_app.js +20 -0
- package/templates/bases/next/pages-router/js/src/pages/_document.js +15 -0
- package/templates/bases/next/pages-router/js/src/pages/api/hello.js +5 -0
- package/templates/bases/next/pages-router/js/src/pages/blog/[slug].js +41 -0
- package/templates/bases/next/pages-router/js/src/pages/index.js +77 -0
- package/templates/bases/next/pages-router/js/src/styles/Home.module.css +149 -0
- package/templates/bases/next/pages-router/js/src/styles/globals.css +42 -0
- package/templates/bases/next/pages-router/ts/.provenance.json +19 -0
- package/templates/bases/next/pages-router/ts/README.md +40 -0
- package/templates/bases/next/pages-router/ts/next.config.ts +8 -0
- package/templates/bases/next/pages-router/ts/package.json +21 -0
- package/templates/bases/next/pages-router/ts/public/favicon.ico +0 -0
- package/templates/bases/next/pages-router/ts/public/file.svg +1 -0
- package/templates/bases/next/pages-router/ts/public/globe.svg +1 -0
- package/templates/bases/next/pages-router/ts/public/next.svg +1 -0
- package/templates/bases/next/pages-router/ts/public/vercel.svg +1 -0
- package/templates/bases/next/pages-router/ts/public/window.svg +1 -0
- package/templates/bases/next/pages-router/ts/src/pages/404.tsx +35 -0
- package/templates/bases/next/pages-router/ts/src/pages/500.tsx +35 -0
- package/templates/bases/next/pages-router/ts/src/pages/_app.tsx +21 -0
- package/templates/bases/next/pages-router/ts/src/pages/_document.tsx +15 -0
- package/templates/bases/next/pages-router/ts/src/pages/api/hello.ts +13 -0
- package/templates/bases/next/pages-router/ts/src/pages/blog/[slug].tsx +46 -0
- package/templates/bases/next/pages-router/ts/src/pages/index.tsx +77 -0
- package/templates/bases/next/pages-router/ts/src/styles/Home.module.css +149 -0
- package/templates/bases/next/pages-router/ts/src/styles/globals.css +42 -0
- package/templates/bases/next/pages-router/ts/tsconfig.json +29 -0
- package/templates/conditional/linting/biome/biome.json +31 -0
- package/templates/conditional/next/config/cloudflare/next.config.mjs +6 -0
- package/templates/conditional/next/config/cloudflare/next.config.ts +7 -0
- package/templates/conditional/next/config/node/next.config.mjs +6 -0
- package/templates/conditional/next/config/node/next.config.ts +7 -0
- package/templates/conditional/next/config/static/next.config.mjs +6 -0
- package/templates/conditional/next/config/static/next.config.ts +7 -0
- package/templates/conditional/next/config/turbopack/next.config.mjs +7 -0
- package/templates/conditional/next/config/turbopack/next.config.ts +8 -0
- package/templates/conditional/next/config/vercel/next.config.mjs +6 -0
- package/templates/conditional/next/config/vercel/next.config.ts +7 -0
- package/templates/conditional/next/config/webpack/next.config.mjs +9 -0
- package/templates/conditional/next/config/webpack/next.config.ts +10 -0
- package/templates/conditional/next/font/BUILD_SIZE_NOTE.md +17 -0
- package/templates/conditional/next/font/app-router/src/app/layout.js +25 -0
- package/templates/conditional/next/font/app-router/src/app/layout.tsx +30 -0
- package/templates/conditional/next/font/pages-router/src/pages/_app.js +20 -0
- package/templates/conditional/next/font/pages-router/src/pages/_app.tsx +21 -0
- package/templates/conditional/next/font/pages-router/src/pages/_document.js +18 -0
- package/templates/conditional/next/font/pages-router/src/pages/_document.tsx +18 -0
- package/templates/conditional/next/font/src/app/layout.js +25 -0
- package/templates/conditional/next/font/src/app/layout.tsx +30 -0
- package/templates/conditional/next/font/src/lib/fonts.js +11 -0
- package/templates/conditional/next/font/src/lib/fonts.ts +11 -0
- package/templates/conditional/next/font/src/pages/_app.js +20 -0
- package/templates/conditional/next/font/src/pages/_app.tsx +21 -0
- package/templates/conditional/next/font/src/pages/_document.js +18 -0
- package/templates/conditional/next/font/src/pages/_document.tsx +18 -0
- package/templates/conditional/next/image/BUILD_SIZE_NOTE.md +15 -0
- package/templates/conditional/next/image/app-router/src/components/ImageExample.jsx +34 -0
- package/templates/conditional/next/image/app-router/src/components/ImageExample.tsx +44 -0
- package/templates/conditional/next/image/pages-router/src/components/ImageExample.jsx +34 -0
- package/templates/conditional/next/image/pages-router/src/components/ImageExample.tsx +44 -0
- package/templates/conditional/next/image/src/components/ImageExample.jsx +44 -0
- package/templates/conditional/next/image/src/components/ImageExample.tsx +54 -0
- package/templates/conditional/next/image/src/components/image/index.js +1 -0
- package/templates/conditional/next/image/src/components/image/index.ts +2 -0
- package/templates/conditional/next/server-components/README.md +13 -0
- package/templates/conditional/next/server-components/eslint.config.mjs +47 -0
- package/templates/conditional/next/server-components/rules/no-server-imports-in-client.js +89 -0
- package/templates/conditional/next/server-components/rules/no-server-imports-in-client.mjs +88 -0
- package/templates/conditional/next/server-components/src/components/boundaries/ClientCounter.jsx +48 -0
- package/templates/conditional/next/server-components/src/components/boundaries/ClientCounter.tsx +53 -0
- package/templates/conditional/next/server-components/src/components/boundaries/ServerCard.jsx +41 -0
- package/templates/conditional/next/server-components/src/components/boundaries/ServerCard.tsx +46 -0
- package/templates/conditional/next/server-components/src/components/boundaries/index.js +2 -0
- package/templates/conditional/next/server-components/src/components/boundaries/index.ts +4 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# create-lumen
|
|
2
2
|
|
|
3
|
-
A scaffolder that generates production-ready React + Vite projects (feature-based, type-based, hybrid, or none
|
|
3
|
+
A scaffolder that generates production-ready **React + Vite** or **Next.js** projects (App Router / Pages Router), with a choice of architecture: feature-based, type-based, hybrid, or none.
|
|
4
4
|
|
|
5
5
|
Note: this repository is the CLI scaffolder itself, not a generated app. Generated projects live in the target folder you create.
|
|
6
6
|
|
|
@@ -14,6 +14,8 @@ cd my-app
|
|
|
14
14
|
npm run dev
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
+
> The v2 line (React + Vite + Next.js, manifest v2) is available on the `beta` dist-tag while v2 is in prerelease: `npm create lumen@beta my-app`.
|
|
18
|
+
|
|
17
19
|
### Non-interactive flags
|
|
18
20
|
|
|
19
21
|
Quick Setup (TypeScript + Tailwind + Feature-based + Router + ESLint + Prettier + Vitest), no prompts:
|
|
@@ -26,20 +28,28 @@ npm create lumen -- -y my-app
|
|
|
26
28
|
npm create lumen my-app -- --yes
|
|
27
29
|
```
|
|
28
30
|
|
|
29
|
-
Scaffold using a template preset (`react-ts`, `react-js`, `react-type-ts`, `react-type-js`):
|
|
31
|
+
Scaffold using a template preset (`react-ts`, `react-js`, `react-type-ts`, `react-type-js`, `next-ts`, `next-js`, `next-pages-ts`, `next-pages-js`):
|
|
30
32
|
|
|
31
33
|
```bash
|
|
32
34
|
npm create lumen my-app -- --template react-ts
|
|
33
35
|
# or
|
|
34
|
-
npm create lumen my-app -- -t
|
|
36
|
+
npm create lumen my-app -- -t next-ts
|
|
35
37
|
```
|
|
36
38
|
|
|
37
39
|
Choose framework and architecture directly:
|
|
38
40
|
|
|
39
41
|
```bash
|
|
40
42
|
npm create lumen my-app -- --framework react --arch none
|
|
43
|
+
|
|
44
|
+
# Next.js — the router is asked interactively (App Router recommended):
|
|
45
|
+
npm create lumen my-app -- -f next
|
|
46
|
+
# ...or pin the variant outright:
|
|
47
|
+
npm create lumen my-app -- -f next:app-router
|
|
48
|
+
npm create lumen my-app -- -f next:pages-router
|
|
41
49
|
```
|
|
42
50
|
|
|
51
|
+
Interactively, the framework is the first prompt (React + Vite / Next.js), followed by a router step when Next.js is selected; every later option gates on that choice.
|
|
52
|
+
|
|
43
53
|
Drive scaffolding directly from a manifest file or inline JSON (manifest v2):
|
|
44
54
|
|
|
45
55
|
```bash
|
|
@@ -70,20 +80,25 @@ create-lumen my-app # after npm link
|
|
|
70
80
|
|
|
71
81
|
## Features
|
|
72
82
|
|
|
83
|
+
- **Two frameworks:** React + Vite (SPA) or Next.js (App Router / Pages Router) — selected interactively or via `-f`
|
|
73
84
|
- Architecture choice: feature-based, type-based, hybrid, or none (per-framework availability)
|
|
74
85
|
- TypeScript or JavaScript output
|
|
75
86
|
- CSS frameworks: Tailwind CSS v4 (CSS-first `@theme`, v3 dropped) or none
|
|
87
|
+
- **UI kit: shadcn/ui** (gated to Tailwind; primitives + `cn` helper land in the mapped `paths.ui`)
|
|
76
88
|
- Optional state management: Zustand or Redux Toolkit
|
|
77
|
-
- Optional router (React Router)
|
|
78
|
-
- Optional testing: Vitest or Jest
|
|
89
|
+
- Optional router (React Router — Vite only; Next.js uses filesystem routing)
|
|
90
|
+
- Optional testing: Vitest or Jest (Next.js defaults to none until a Next-native overlay is verified)
|
|
91
|
+
- **Next.js-native overlays:** server/client boundary demos + `no-server-imports-in-client` ESLint rule, `next/font` (Geist), `next/image`, filesystem routing examples, route handlers (`route.ts`) / API routes (`pages/api`)
|
|
92
|
+
- **Next.js options:** `bundler: turbopack|webpack`, `adapter: node|vercel|cloudflare|static` (`next.config` overlays), `reactCompiler`, `linter: biome` — all validated against the capability model
|
|
79
93
|
- Linting: ESLint (default), Oxlint, or Biome
|
|
80
94
|
- Code formatter: Prettier or Oxfmt (chosen after the linter; `eslint-config-prettier` is auto-wired for the ESLint + Prettier combo)
|
|
81
|
-
- Manifest v2: Emits a deterministic `lumen.config.json`
|
|
95
|
+
- Manifest v2: Emits a deterministic `lumen.config.json` validated against JSON Schema Draft 2020-12, including architecture validation modes and harness command configuration.
|
|
82
96
|
- Explicit path mapping: Target directories declared for `lumen-cli` code generation
|
|
83
97
|
- Optional Axios setup and icon libraries
|
|
84
98
|
- Auto `git init`, generated `README` (with a project description reflecting the chosen tooling) and `LICENSE`
|
|
85
99
|
- `.env.example` scaffolded, and the generated `.gitignore` excludes env files (`.env`, `.env.*`) while keeping `.env.example`
|
|
86
100
|
- `@/` path alias configured (`tsconfig`/`jsconfig` + Vite)
|
|
101
|
+
- **Agent docs:** optional `.lumen/` context directory (project, architecture, conventions) via prompt or `--agent-docs`
|
|
87
102
|
|
|
88
103
|
Your selected options are cached and offered as defaults on subsequent runs.
|
|
89
104
|
|
|
@@ -206,6 +221,9 @@ The manifest now includes:
|
|
|
206
221
|
### Ecosystem Documentation & Contracts
|
|
207
222
|
|
|
208
223
|
- **[Documentation Index](./docs/README.md):** Complete overview of specifications, ADRs, and developer guides.
|
|
224
|
+
- **[Next.js App Router Guide](./docs/next-app-router.md):** App Router scaffold, filesystem routing, route handlers, server/client boundaries, `next/font` and `next/image`.
|
|
225
|
+
- **[Next.js Pages Router Guide](./docs/next-pages-router.md):** Pages Router scaffold, API routes, `_app`/`_document` wiring.
|
|
226
|
+
- **[Deployment Adapters Guide](./docs/next-adapters.md):** Adapter matrix (Node, Vercel, Cloudflare, static), bundler choice and Biome setup for Next.js.
|
|
209
227
|
- **[Generator Engine & Capabilities Guide (M2)](./docs/engine-capabilities.md):** Capability model, template composition, shadcn/ui on Tailwind v4, architecture presets, and Bootstrap removal.
|
|
210
228
|
- **[Manifest v2 Overview](./docs/manifest-v2.md):** Specification of the nested schema, validation behavior, and the new harness and architecture validation fields.
|
|
211
229
|
- **[Shared Contract: `create-lumen` ↔ `lumen-cli`](./docs/contracts/manifest-v2-contract.md):** The agreed contract for path mapping, barrel conventions, version negotiation, and the harness/configuration interface.
|
package/bin/cli.js
CHANGED
|
@@ -25,7 +25,7 @@ console.log(
|
|
|
25
25
|
chalk.bold.cyan("\n ✦ LUMEN") +
|
|
26
26
|
chalk.gray(` v${version}`) +
|
|
27
27
|
chalk.gray(
|
|
28
|
-
"\n Scaffold a React
|
|
28
|
+
"\n Scaffold a React, Vite, or Next.js project with architecture choice\n"
|
|
29
29
|
)
|
|
30
30
|
);
|
|
31
31
|
|
|
@@ -36,6 +36,7 @@ main({
|
|
|
36
36
|
projectName: cliArgs.projectName,
|
|
37
37
|
manifest: cliArgs.manifest,
|
|
38
38
|
template: cliArgs.template,
|
|
39
|
+
framework: cliArgs.framework,
|
|
39
40
|
arch: cliArgs.arch,
|
|
40
41
|
}).catch((e) => {
|
|
41
42
|
console.error(chalk.red("\nError:"), e.message || e);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-lumen",
|
|
3
|
-
"version": "2.0.0-
|
|
3
|
+
"version": "2.0.0-beta.1",
|
|
4
4
|
"description": "Scaffold a React + Vite project with architecture choice: feature-based, type-based, hybrid, or none.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
},
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
11
|
-
"url": "https://github.com/
|
|
11
|
+
"url": "https://github.com/strophix-software/create-lumen"
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"bin/",
|
package/src/cli-args.js
CHANGED
|
@@ -6,7 +6,6 @@ import { parseManifest } from "./manifest/schema.js";
|
|
|
6
6
|
import {
|
|
7
7
|
normalizeFramework,
|
|
8
8
|
isPromptVisible,
|
|
9
|
-
getDefaultResponses,
|
|
10
9
|
} from "./engine/capabilities.js";
|
|
11
10
|
|
|
12
11
|
export const PRESETS = {
|
|
@@ -180,6 +179,78 @@ export const PRESETS = {
|
|
|
180
179
|
gitInit: true,
|
|
181
180
|
readme: true,
|
|
182
181
|
},
|
|
182
|
+
"next-ts": {
|
|
183
|
+
frameworkName: "next",
|
|
184
|
+
frameworkVariant: "app-router",
|
|
185
|
+
architecture: "feature-based",
|
|
186
|
+
language: "ts",
|
|
187
|
+
cssFramework: "tailwind",
|
|
188
|
+
testing: "vitest",
|
|
189
|
+
router: false,
|
|
190
|
+
bundler: "turbopack",
|
|
191
|
+
stateManagement: "none",
|
|
192
|
+
iconLibrary: "none",
|
|
193
|
+
apiClient: "none",
|
|
194
|
+
linter: "eslint",
|
|
195
|
+
formatter: "prettier",
|
|
196
|
+
docsLanguage: "en",
|
|
197
|
+
gitInit: true,
|
|
198
|
+
readme: true,
|
|
199
|
+
},
|
|
200
|
+
"next-js": {
|
|
201
|
+
frameworkName: "next",
|
|
202
|
+
frameworkVariant: "app-router",
|
|
203
|
+
architecture: "feature-based",
|
|
204
|
+
language: "js",
|
|
205
|
+
cssFramework: "tailwind",
|
|
206
|
+
testing: "vitest",
|
|
207
|
+
router: false,
|
|
208
|
+
bundler: "turbopack",
|
|
209
|
+
stateManagement: "none",
|
|
210
|
+
iconLibrary: "none",
|
|
211
|
+
apiClient: "none",
|
|
212
|
+
linter: "eslint",
|
|
213
|
+
formatter: "prettier",
|
|
214
|
+
docsLanguage: "en",
|
|
215
|
+
gitInit: true,
|
|
216
|
+
readme: true,
|
|
217
|
+
},
|
|
218
|
+
"next-pages-ts": {
|
|
219
|
+
frameworkName: "next",
|
|
220
|
+
frameworkVariant: "pages-router",
|
|
221
|
+
architecture: "feature-based",
|
|
222
|
+
language: "ts",
|
|
223
|
+
cssFramework: "tailwind",
|
|
224
|
+
testing: "vitest",
|
|
225
|
+
router: false,
|
|
226
|
+
bundler: "turbopack",
|
|
227
|
+
stateManagement: "none",
|
|
228
|
+
iconLibrary: "none",
|
|
229
|
+
apiClient: "none",
|
|
230
|
+
linter: "eslint",
|
|
231
|
+
formatter: "prettier",
|
|
232
|
+
docsLanguage: "en",
|
|
233
|
+
gitInit: true,
|
|
234
|
+
readme: true,
|
|
235
|
+
},
|
|
236
|
+
"next-pages-js": {
|
|
237
|
+
frameworkName: "next",
|
|
238
|
+
frameworkVariant: "pages-router",
|
|
239
|
+
architecture: "feature-based",
|
|
240
|
+
language: "js",
|
|
241
|
+
cssFramework: "tailwind",
|
|
242
|
+
testing: "vitest",
|
|
243
|
+
router: false,
|
|
244
|
+
bundler: "turbopack",
|
|
245
|
+
stateManagement: "none",
|
|
246
|
+
iconLibrary: "none",
|
|
247
|
+
apiClient: "none",
|
|
248
|
+
linter: "eslint",
|
|
249
|
+
formatter: "prettier",
|
|
250
|
+
docsLanguage: "en",
|
|
251
|
+
gitInit: true,
|
|
252
|
+
readme: true,
|
|
253
|
+
},
|
|
183
254
|
};
|
|
184
255
|
|
|
185
256
|
/**
|
|
@@ -207,6 +278,13 @@ export function parseCliArgs(argv = process.argv.slice(2)) {
|
|
|
207
278
|
framework: { type: "string", short: "f" },
|
|
208
279
|
arch: { type: "string", short: "a" },
|
|
209
280
|
architecture: { type: "string" },
|
|
281
|
+
bundler: { type: "string", short: "b" },
|
|
282
|
+
adapter: { type: "string" },
|
|
283
|
+
"react-compiler": { type: "boolean" },
|
|
284
|
+
reactCompiler: { type: "boolean" },
|
|
285
|
+
"agent-docs": { type: "boolean" },
|
|
286
|
+
agentDocs: { type: "boolean" },
|
|
287
|
+
linter: { type: "string" },
|
|
210
288
|
help: { type: "boolean", short: "h", default: false },
|
|
211
289
|
version: { type: "boolean", short: "v", default: false },
|
|
212
290
|
},
|
|
@@ -223,6 +301,12 @@ export function parseCliArgs(argv = process.argv.slice(2)) {
|
|
|
223
301
|
else if (arch === "component" || arch === "component-based" || arch === "type") arch = "type-based";
|
|
224
302
|
}
|
|
225
303
|
|
|
304
|
+
const bundler = values.bundler ? values.bundler.trim().toLowerCase() : null;
|
|
305
|
+
const adapter = values.adapter ? values.adapter.trim().toLowerCase() : null;
|
|
306
|
+
const reactCompiler = values["react-compiler"] ?? values.reactCompiler ?? null;
|
|
307
|
+
const agentDocs = values["agent-docs"] ?? values.agentDocs ?? null;
|
|
308
|
+
const linter = values.linter ? values.linter.trim().toLowerCase() : null;
|
|
309
|
+
|
|
226
310
|
return {
|
|
227
311
|
projectName,
|
|
228
312
|
quickSetup: Boolean(values.yes),
|
|
@@ -230,6 +314,11 @@ export function parseCliArgs(argv = process.argv.slice(2)) {
|
|
|
230
314
|
template: values.template || null,
|
|
231
315
|
framework: values.framework ? values.framework.trim() : null,
|
|
232
316
|
arch,
|
|
317
|
+
bundler,
|
|
318
|
+
adapter,
|
|
319
|
+
reactCompiler,
|
|
320
|
+
agentDocs,
|
|
321
|
+
linter,
|
|
233
322
|
help: Boolean(values.help),
|
|
234
323
|
version: Boolean(values.version),
|
|
235
324
|
positionals,
|
|
@@ -278,6 +367,8 @@ export function manifestToResponses(manifest, projectName) {
|
|
|
278
367
|
const framework = normalizeFramework({ name: frameworkName, variant: frameworkVariant });
|
|
279
368
|
const canClientRoute = isPromptVisible(framework, "router");
|
|
280
369
|
const supportsBundler = isPromptVisible(framework, "bundler");
|
|
370
|
+
const supportsAdapter = isPromptVisible(framework, "adapter");
|
|
371
|
+
const supportsCompiler = isPromptVisible(framework, "reactCompiler");
|
|
281
372
|
|
|
282
373
|
return {
|
|
283
374
|
projectName,
|
|
@@ -287,7 +378,10 @@ export function manifestToResponses(manifest, projectName) {
|
|
|
287
378
|
supportsBundler && manifest.framework?.bundler
|
|
288
379
|
? manifest.framework.bundler
|
|
289
380
|
: undefined,
|
|
290
|
-
adapter:
|
|
381
|
+
adapter:
|
|
382
|
+
supportsAdapter && manifest.framework?.adapter
|
|
383
|
+
? manifest.framework.adapter
|
|
384
|
+
: undefined,
|
|
291
385
|
architecture: manifest.architecture?.type || "feature-based",
|
|
292
386
|
language: manifest.tooling?.language || "ts",
|
|
293
387
|
cssFramework: manifest.styling?.engine || "tailwind",
|
|
@@ -295,10 +389,12 @@ export function manifestToResponses(manifest, projectName) {
|
|
|
295
389
|
formatter: manifest.tooling?.formatter || "prettier",
|
|
296
390
|
uiKit: manifest.ui?.kit || "none",
|
|
297
391
|
docsLanguage: manifest.docs?.language || "en",
|
|
298
|
-
reactCompiler: manifest.reactCompiler,
|
|
392
|
+
reactCompiler: supportsCompiler ? manifest.reactCompiler : undefined,
|
|
299
393
|
agentDocs: manifest.agentDocs,
|
|
300
|
-
// Sensible defaults for scaffolder conditional passes
|
|
301
|
-
|
|
394
|
+
// Sensible defaults for scaffolder conditional passes (Next.js ships no
|
|
395
|
+
// verified test-runner overlay yet, so it defaults to none; explicit
|
|
396
|
+
// vitest/jest selection still applies the standard overlays)
|
|
397
|
+
testing: frameworkName === "next" ? "none" : "vitest",
|
|
302
398
|
router: canClientRoute,
|
|
303
399
|
stateManagement: "none",
|
|
304
400
|
iconLibrary: "none",
|
|
@@ -335,6 +431,10 @@ ${chalk.bold("PRESETS")}
|
|
|
335
431
|
${chalk.cyan("react-type-js")} React + Vite + JavaScript (type-based)
|
|
336
432
|
${chalk.cyan("react-none-ts")} React + Vite + TypeScript (none)
|
|
337
433
|
${chalk.cyan("react-none-js")} React + Vite + JavaScript (none)
|
|
434
|
+
${chalk.cyan("next-ts")} Next.js App Router + TypeScript (feature-based)
|
|
435
|
+
${chalk.cyan("next-js")} Next.js App Router + JavaScript (feature-based)
|
|
436
|
+
${chalk.cyan("next-pages-ts")} Next.js Pages Router + TypeScript (feature-based)
|
|
437
|
+
${chalk.cyan("next-pages-js")} Next.js Pages Router + JavaScript (feature-based)
|
|
338
438
|
|
|
339
439
|
${chalk.bold("EXAMPLES")}
|
|
340
440
|
${chalk.gray("# Interactive setup")}
|
package/src/configure.js
CHANGED
|
@@ -166,12 +166,16 @@ async function configurePackageJson(projectPath, language) {
|
|
|
166
166
|
|
|
167
167
|
if (!pkg.scripts) pkg.scripts = {};
|
|
168
168
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
169
|
+
// Fill defaults only — never overwrite scripts owned by the base template
|
|
170
|
+
// (Next.js bases ship next dev/build/start) or merged overlay fragments
|
|
171
|
+
// (e.g. the bundler-aware dev script). React/Vite bases already carry the
|
|
172
|
+
// vite commands, so this is a no-op there too.
|
|
173
|
+
pkg.scripts.dev ??= "vite";
|
|
174
|
+
pkg.scripts.build ??= "vite build";
|
|
175
|
+
pkg.scripts.preview ??= "vite preview";
|
|
172
176
|
|
|
173
177
|
if (language === "ts") {
|
|
174
|
-
pkg.scripts.typecheck
|
|
178
|
+
pkg.scripts.typecheck ??= "tsc -b";
|
|
175
179
|
}
|
|
176
180
|
|
|
177
181
|
await fsp.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
package/src/dependencies.js
CHANGED
|
@@ -40,6 +40,10 @@ export async function installAllDeps(responses, pkg, cwd) {
|
|
|
40
40
|
// the conditional wiring stays verifiable without a network install.
|
|
41
41
|
export function computeDeps(responses) {
|
|
42
42
|
const deps = [];
|
|
43
|
+
const fwName =
|
|
44
|
+
typeof responses.framework === "string"
|
|
45
|
+
? responses.framework
|
|
46
|
+
: (responses.framework?.name ?? responses.frameworkName ?? "react");
|
|
43
47
|
const cssDevDeps = [];
|
|
44
48
|
const testingDevDeps = [];
|
|
45
49
|
const linterDevDeps = [];
|
|
@@ -47,7 +51,7 @@ export function computeDeps(responses) {
|
|
|
47
51
|
|
|
48
52
|
// CSS framework
|
|
49
53
|
if (responses.cssFramework === "tailwind") {
|
|
50
|
-
if (
|
|
54
|
+
if (fwName === "next") {
|
|
51
55
|
cssDevDeps.push("tailwindcss", "@tailwindcss/postcss", "postcss");
|
|
52
56
|
} else {
|
|
53
57
|
cssDevDeps.push("tailwindcss", "@tailwindcss/vite");
|
|
@@ -103,7 +107,7 @@ export function computeDeps(responses) {
|
|
|
103
107
|
|
|
104
108
|
// Linter
|
|
105
109
|
if (responses.linter === "eslint") {
|
|
106
|
-
if (
|
|
110
|
+
if (fwName === "next") {
|
|
107
111
|
linterDevDeps.push("eslint", "eslint-config-next");
|
|
108
112
|
} else {
|
|
109
113
|
linterDevDeps.push("eslint", "@eslint/js", "eslint-plugin-react-hooks", "eslint-plugin-react-refresh", "globals");
|
|
@@ -113,6 +117,8 @@ export function computeDeps(responses) {
|
|
|
113
117
|
}
|
|
114
118
|
} else if (responses.linter === "oxlint") {
|
|
115
119
|
linterDevDeps.push("oxlint");
|
|
120
|
+
} else if (responses.linter === "biome") {
|
|
121
|
+
linterDevDeps.push("@biomejs/biome");
|
|
116
122
|
}
|
|
117
123
|
|
|
118
124
|
// Formatter
|
|
@@ -153,6 +153,9 @@ export function isOptionCompatible(framework, optionKey, optionValue) {
|
|
|
153
153
|
case "bundler":
|
|
154
154
|
return desc.allowedBundlers.includes(optionValue);
|
|
155
155
|
case "adapter":
|
|
156
|
+
if (optionValue === "none") {
|
|
157
|
+
return desc.allowedAdapters.length > 0;
|
|
158
|
+
}
|
|
156
159
|
return desc.allowedAdapters.includes(optionValue);
|
|
157
160
|
case "router":
|
|
158
161
|
// If framework has filesystem routing, external router options (true) are incompatible
|
|
@@ -160,6 +163,11 @@ export function isOptionCompatible(framework, optionKey, optionValue) {
|
|
|
160
163
|
return optionValue === false || optionValue === "none";
|
|
161
164
|
}
|
|
162
165
|
return true;
|
|
166
|
+
case "reactCompiler":
|
|
167
|
+
if (optionValue === true) {
|
|
168
|
+
return hasCapability(framework, CAPABILITIES.REACT_COMPILER);
|
|
169
|
+
}
|
|
170
|
+
return true;
|
|
163
171
|
default:
|
|
164
172
|
return true;
|
|
165
173
|
}
|
|
@@ -318,10 +326,11 @@ export function getDefaultResponses(framework, { projectName = "my-app" } = {})
|
|
|
318
326
|
architecture: "feature-based",
|
|
319
327
|
language: "ts",
|
|
320
328
|
cssFramework: "tailwind",
|
|
321
|
-
testing: "
|
|
329
|
+
testing: "none",
|
|
322
330
|
router: false,
|
|
323
331
|
bundler: "turbopack",
|
|
324
332
|
adapter: "none",
|
|
333
|
+
uiKit: "none",
|
|
325
334
|
stateManagement: "none",
|
|
326
335
|
iconLibrary: "none",
|
|
327
336
|
apiClient: "none",
|
|
@@ -342,6 +351,7 @@ export function getDefaultResponses(framework, { projectName = "my-app" } = {})
|
|
|
342
351
|
cssFramework: "tailwind",
|
|
343
352
|
testing: "vitest",
|
|
344
353
|
router: true,
|
|
354
|
+
uiKit: "none",
|
|
345
355
|
stateManagement: "none",
|
|
346
356
|
iconLibrary: "none",
|
|
347
357
|
apiClient: "none",
|
|
@@ -369,6 +379,17 @@ export function sanitizeResponsesForFramework(framework, responses = {}) {
|
|
|
369
379
|
if (!isPromptVisible(fw, "router")) {
|
|
370
380
|
sanitized.router = false;
|
|
371
381
|
}
|
|
382
|
+
if (!isPromptVisible(fw, "bundler")) {
|
|
383
|
+
delete sanitized.bundler;
|
|
384
|
+
}
|
|
385
|
+
if (!isPromptVisible(fw, "adapter")) {
|
|
386
|
+
delete sanitized.adapter;
|
|
387
|
+
}
|
|
388
|
+
if (!isPromptVisible(fw, "reactCompiler")) {
|
|
389
|
+
if (sanitized.reactCompiler !== undefined) {
|
|
390
|
+
sanitized.reactCompiler = false;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
372
393
|
|
|
373
394
|
for (const [key, val] of Object.entries(sanitized)) {
|
|
374
395
|
if (val === undefined || val === null) continue;
|
|
@@ -44,6 +44,7 @@ export const TOOLING_ORDER = [
|
|
|
44
44
|
"testing",
|
|
45
45
|
"linter",
|
|
46
46
|
"feature-script",
|
|
47
|
+
"next-config",
|
|
47
48
|
"formatter",
|
|
48
49
|
];
|
|
49
50
|
|
|
@@ -149,6 +150,15 @@ export function resolveFragments(responses = {}, templatesDir) {
|
|
|
149
150
|
try { await fsp.rm(path.join(projectPath, "src", "App.jsx"), { force: true }); } catch {}
|
|
150
151
|
try { await fsp.rm(path.join(projectPath, "src", "index.css"), { force: true }); } catch {}
|
|
151
152
|
try { await fsp.rm(path.join(projectPath, "src", "App.css"), { force: true }); } catch {}
|
|
153
|
+
if (fw.name === "next") {
|
|
154
|
+
// Next cleanup: remove Vite defaults without touching app/
|
|
155
|
+
try { await fsp.rm(path.join(projectPath, "src", "main.tsx"), { force: true }); } catch {}
|
|
156
|
+
try { await fsp.rm(path.join(projectPath, "src", "main.jsx"), { force: true }); } catch {}
|
|
157
|
+
try { await fsp.rm(path.join(projectPath, "index.html"), { force: true }); } catch {}
|
|
158
|
+
try { await fsp.rm(path.join(projectPath, "vite.config.ts"), { force: true }); } catch {}
|
|
159
|
+
try { await fsp.rm(path.join(projectPath, "vite.config.js"), { force: true }); } catch {}
|
|
160
|
+
try { await fsp.rm(path.join(projectPath, "public", "vite.svg"), { force: true }); } catch {}
|
|
161
|
+
}
|
|
152
162
|
},
|
|
153
163
|
});
|
|
154
164
|
|
|
@@ -406,6 +416,23 @@ export function resolveFragments(responses = {}, templatesDir) {
|
|
|
406
416
|
} catch {}
|
|
407
417
|
},
|
|
408
418
|
});
|
|
419
|
+
} else if (responses.linter === "biome") {
|
|
420
|
+
fragments.push({
|
|
421
|
+
scope: FRAGMENT_SCOPES.TOOLING,
|
|
422
|
+
category: "linter",
|
|
423
|
+
id: "tooling:linter:biome",
|
|
424
|
+
scripts: {
|
|
425
|
+
lint: "biome check .",
|
|
426
|
+
"lint:fix": "biome check --write .",
|
|
427
|
+
},
|
|
428
|
+
action: async ({ projectPath }) => {
|
|
429
|
+
const configSrc = path.join(templatesDir, "conditional", "linting", "biome", "biome.json");
|
|
430
|
+
try {
|
|
431
|
+
await fsp.access(configSrc);
|
|
432
|
+
await fsp.copyFile(configSrc, path.join(projectPath, "biome.json"));
|
|
433
|
+
} catch {}
|
|
434
|
+
},
|
|
435
|
+
});
|
|
409
436
|
}
|
|
410
437
|
|
|
411
438
|
// 5.7 Feature Script (Feature-based only)
|
|
@@ -437,6 +464,71 @@ export function resolveFragments(responses = {}, templatesDir) {
|
|
|
437
464
|
});
|
|
438
465
|
}
|
|
439
466
|
|
|
467
|
+
// 5.75 Next.js Configuration & Adapter Overlays
|
|
468
|
+
if (fw.name === "next") {
|
|
469
|
+
const nextScripts = {};
|
|
470
|
+
if (responses.bundler === "turbopack") {
|
|
471
|
+
nextScripts.dev = "next dev --turbopack";
|
|
472
|
+
} else if (responses.bundler === "webpack") {
|
|
473
|
+
nextScripts.dev = "next dev --webpack";
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
fragments.push({
|
|
477
|
+
scope: FRAGMENT_SCOPES.TOOLING,
|
|
478
|
+
category: "next-config",
|
|
479
|
+
id: "tooling:next:config",
|
|
480
|
+
scripts: nextScripts,
|
|
481
|
+
action: async ({ projectPath }) => {
|
|
482
|
+
const configExt = language === "ts" ? "ts" : "mjs";
|
|
483
|
+
|
|
484
|
+
// Apply adapter overlay if specified and not "none"
|
|
485
|
+
if (responses.adapter && responses.adapter !== "none") {
|
|
486
|
+
const adapterConfigSrc = path.join(
|
|
487
|
+
templatesDir,
|
|
488
|
+
"conditional",
|
|
489
|
+
"next",
|
|
490
|
+
"config",
|
|
491
|
+
responses.adapter,
|
|
492
|
+
`next.config.${configExt}`
|
|
493
|
+
);
|
|
494
|
+
try {
|
|
495
|
+
await fsp.access(adapterConfigSrc);
|
|
496
|
+
await fsp.copyFile(adapterConfigSrc, path.join(projectPath, `next.config.${configExt}`));
|
|
497
|
+
} catch {}
|
|
498
|
+
} else if (responses.bundler === "turbopack" || responses.bundler === "webpack") {
|
|
499
|
+
// If no adapter specified, but bundler config overlay exists, apply bundler overlay
|
|
500
|
+
const bundlerConfigSrc = path.join(
|
|
501
|
+
templatesDir,
|
|
502
|
+
"conditional",
|
|
503
|
+
"next",
|
|
504
|
+
"config",
|
|
505
|
+
responses.bundler,
|
|
506
|
+
`next.config.${configExt}`
|
|
507
|
+
);
|
|
508
|
+
try {
|
|
509
|
+
await fsp.access(bundlerConfigSrc);
|
|
510
|
+
await fsp.copyFile(bundlerConfigSrc, path.join(projectPath, `next.config.${configExt}`));
|
|
511
|
+
} catch {}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// Apply reactCompiler flag to next.config if enabled
|
|
515
|
+
if (responses.reactCompiler === true) {
|
|
516
|
+
const targetConfigPath = path.join(projectPath, `next.config.${configExt}`);
|
|
517
|
+
try {
|
|
518
|
+
let content = await fsp.readFile(targetConfigPath, "utf8");
|
|
519
|
+
if (!content.includes("reactCompiler")) {
|
|
520
|
+
content = content.replace(
|
|
521
|
+
/const nextConfig(?::\s*NextConfig)?\s*=\s*\{/,
|
|
522
|
+
(match) => `${match}\n reactCompiler: true,`
|
|
523
|
+
);
|
|
524
|
+
await fsp.writeFile(targetConfigPath, content, "utf8");
|
|
525
|
+
}
|
|
526
|
+
} catch {}
|
|
527
|
+
}
|
|
528
|
+
},
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
|
|
440
532
|
// 5.8 Formatter
|
|
441
533
|
if (responses.formatter && responses.formatter !== "none") {
|
|
442
534
|
const isPrettier = responses.formatter === "prettier";
|
|
@@ -125,7 +125,7 @@ export class NextAppRouterProvider extends BaseProvider {
|
|
|
125
125
|
getPackageSet({ options = {} } = {}) {
|
|
126
126
|
const isTs = options.language === "ts";
|
|
127
127
|
const deps = {
|
|
128
|
-
next: "^
|
|
128
|
+
next: "^16.0.0",
|
|
129
129
|
react: "^19.0.0",
|
|
130
130
|
"react-dom": "^19.0.0",
|
|
131
131
|
};
|
|
@@ -134,7 +134,7 @@ export class NextAppRouterProvider extends BaseProvider {
|
|
|
134
134
|
devDeps.typescript = "^5.7.0";
|
|
135
135
|
devDeps["@types/react"] = "^19.0.0";
|
|
136
136
|
devDeps["@types/react-dom"] = "^19.0.0";
|
|
137
|
-
devDeps["@types/node"] = "^
|
|
137
|
+
devDeps["@types/node"] = "^22.0.0";
|
|
138
138
|
}
|
|
139
139
|
return {
|
|
140
140
|
dependencies: deps,
|
|
@@ -159,7 +159,7 @@ export class NextPagesRouterProvider extends BaseProvider {
|
|
|
159
159
|
getPackageSet({ options = {} } = {}) {
|
|
160
160
|
const isTs = options.language === "ts";
|
|
161
161
|
const deps = {
|
|
162
|
-
next: "^
|
|
162
|
+
next: "^16.0.0",
|
|
163
163
|
react: "^19.0.0",
|
|
164
164
|
"react-dom": "^19.0.0",
|
|
165
165
|
};
|
|
@@ -168,7 +168,7 @@ export class NextPagesRouterProvider extends BaseProvider {
|
|
|
168
168
|
devDeps.typescript = "^5.7.0";
|
|
169
169
|
devDeps["@types/react"] = "^19.0.0";
|
|
170
170
|
devDeps["@types/react-dom"] = "^19.0.0";
|
|
171
|
-
devDeps["@types/node"] = "^
|
|
171
|
+
devDeps["@types/node"] = "^22.0.0";
|
|
172
172
|
}
|
|
173
173
|
return {
|
|
174
174
|
dependencies: deps,
|
package/src/main.js
CHANGED
|
@@ -12,7 +12,7 @@ import { injectArchitecture, injectConditionals, injectFormatter } from "@/injec
|
|
|
12
12
|
import { getPkgManager } from "@/utils/pkg-manager.js";
|
|
13
13
|
import { handleDevServer } from "@/utils/dev-server.js";
|
|
14
14
|
import { getUserInputs, onCancel } from "@/prompts.js";
|
|
15
|
-
import { runBaseInstall, runGitInit, runViteCreate } from "@/scaffold.js";
|
|
15
|
+
import { runBaseInstall, runGitInit, runViteCreate, scaffoldBase } from "@/scaffold.js";
|
|
16
16
|
import { installAllDeps } from "@/dependencies.js";
|
|
17
17
|
import { generateReadme } from "@/readme.js";
|
|
18
18
|
import { runProjectFormat } from "@/format.js";
|
|
@@ -20,6 +20,8 @@ import { emitManifest } from "@/manifest/emit.js";
|
|
|
20
20
|
import { emitAgentContext } from "@/agent-context.js";
|
|
21
21
|
|
|
22
22
|
import { parseCliArgs, loadManifestSource, manifestToResponses, PRESETS } from "@/cli-args.js";
|
|
23
|
+
import { getProvider } from "@/engine/providers/base-provider.js";
|
|
24
|
+
import { normalizeFramework } from "@/engine/capabilities.js";
|
|
23
25
|
|
|
24
26
|
const __filename = fileURLToPath(import.meta.url);
|
|
25
27
|
const __dirname = path.dirname(__filename);
|
|
@@ -48,6 +50,7 @@ export async function main(options = {}) {
|
|
|
48
50
|
projectName: nameArg,
|
|
49
51
|
manifest: manifestSource,
|
|
50
52
|
template: templateName,
|
|
53
|
+
framework: frameworkArg,
|
|
51
54
|
arch: archArg,
|
|
52
55
|
} = options;
|
|
53
56
|
const pkg = getPkgManager();
|
|
@@ -94,20 +97,40 @@ export async function main(options = {}) {
|
|
|
94
97
|
...preset,
|
|
95
98
|
};
|
|
96
99
|
} else {
|
|
97
|
-
responses = await getUserInputs(projectName, { quickSetup, initialArch: archArg });
|
|
100
|
+
responses = await getUserInputs(projectName, { quickSetup, initialArch: archArg, framework: frameworkArg });
|
|
98
101
|
}
|
|
99
102
|
|
|
100
103
|
const projectPath = path.resolve(CURRENT_DIR, projectName);
|
|
101
104
|
|
|
102
|
-
// 4. Scaffold
|
|
105
|
+
// 4. Scaffold the base project (provider-owned bases; Vite shells out, Next copies)
|
|
106
|
+
const fw = normalizeFramework(
|
|
107
|
+
responses.framework || { name: responses.frameworkName, variant: responses.frameworkVariant }
|
|
108
|
+
);
|
|
103
109
|
const createSpin = spinner();
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
110
|
+
if (fw.name === "next") {
|
|
111
|
+
createSpin.start("Creating your Next.js project...");
|
|
112
|
+
try {
|
|
113
|
+
const provider = getProvider(fw.name, fw.variant);
|
|
114
|
+
const based = await scaffoldBase(projectPath, provider, responses.language, TEMPLATES_DIR);
|
|
115
|
+
if (!based) {
|
|
116
|
+
throw new Error(
|
|
117
|
+
`Next.js base template not found for variant "${fw.variant}" (${responses.language}).`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
createSpin.stop(chalk.green("Project created successfully!"));
|
|
121
|
+
} catch (err) {
|
|
122
|
+
createSpin.stop(chalk.red("Failed to create project."));
|
|
123
|
+
throw err;
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
createSpin.start("Creating your Vite + React project...");
|
|
127
|
+
try {
|
|
128
|
+
await runViteCreate(projectPath, projectName, pkg, responses.language);
|
|
129
|
+
createSpin.stop(chalk.green("Project created successfully!"));
|
|
130
|
+
} catch (err) {
|
|
131
|
+
createSpin.stop(chalk.red("Failed to create project."));
|
|
132
|
+
throw err;
|
|
133
|
+
}
|
|
111
134
|
}
|
|
112
135
|
|
|
113
136
|
// 5. Install base dependencies
|
package/src/manifest/emit.js
CHANGED
|
@@ -64,7 +64,7 @@ export function buildManifest(responses, opts = {}) {
|
|
|
64
64
|
};
|
|
65
65
|
// Include optional axes only if present in responses (future overlays)
|
|
66
66
|
if (responses.bundler) framework.bundler = responses.bundler;
|
|
67
|
-
if (responses.adapter) framework.adapter = responses.adapter;
|
|
67
|
+
if (responses.adapter && responses.adapter !== "none") framework.adapter = responses.adapter;
|
|
68
68
|
|
|
69
69
|
const styling = {
|
|
70
70
|
engine: responses.cssFramework || "tailwind",
|