Skip to content

Commit 65191e3

Browse files
committed
Switch to src/versions.json over versions.ts
1 parent 3d5c79a commit 65191e3

6 files changed

Lines changed: 399 additions & 211 deletions

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Generated at build time
2+
src/versions.json
3+
templates/

packages/create-vite-app/PLAN.md

Lines changed: 34 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -4,46 +4,35 @@
44
Build a CLI scaffolding tool that copies the `examples/react-vanilla-spa/` template and resolves pnpm catalog versions at build time.
55

66
## Requirements Summary
7-
- **Template source**: `examples/react-vanilla-spa/` (no dedicated templates folder)
7+
- **Template source**: `examples/react-vanilla-spa/` (bundled at build time)
88
- **Prompts**: Project name only (using @clack/prompts)
99
- **Versions**: Baked in at build time from `pnpm-workspace.yaml`
1010
- **Post-scaffold**: Auto-detect package manager and install dependencies
1111
- **Skip**: test files, node_modules, dist folders
1212

1313
---
1414

15-
## Implementation Steps
15+
## Implementation (Completed)
1616

1717
### Step 1: Add dependencies
1818
**File**: `packages/create-vite-app/package.json`
1919

20-
Add:
21-
- `@clack/prompts` - interactive CLI prompts
22-
- `yaml` (devDependency) - parse pnpm-workspace.yaml at build time
23-
24-
### Step 2: Create build script to generate versions
25-
**New file**: `packages/create-vite-app/scripts/generate-versions.ts`
26-
27-
This script will:
28-
1. Read `../../pnpm-workspace.yaml` for catalog versions
29-
2. Read `../fastify-vite/package.json` for @fastify/vite version (workspace:^ reference)
30-
3. Parse catalog and catalogs sections
31-
4. Write `src/versions.ts` with resolved versions:
32-
```ts
33-
export const versions = {
34-
'@fastify/vite': '^8.2.3',
35-
'fastify': '^5.6.2',
36-
'vite': '^7.3.0',
37-
'react': '^19.2.3',
38-
'react-dom': '^19.2.3',
39-
'@vitejs/plugin-react': '^5.1.2',
40-
}
41-
```
20+
Added:
21+
- `@clack/prompts` ^0.11.0 - interactive CLI prompts
22+
- `yaml` ^2.8.2 (devDependency) - parse pnpm-workspace.yaml at build time
23+
24+
### Step 2: Create build script
25+
**File**: `packages/create-vite-app/scripts/generate-versions.ts`
26+
27+
This script:
28+
1. Reads `pnpm-workspace.yaml` for catalog versions
29+
2. Reads `packages/fastify-vite/package.json` for @fastify/vite version
30+
3. Writes `src/versions.json` with resolved versions
31+
4. Copies template files from `examples/react-vanilla-spa` to `templates/react-spa`
4232

4333
### Step 3: Update build script in package.json
4434
**File**: `packages/create-vite-app/package.json`
4535

46-
Change build to:
4736
```json
4837
"build": "node scripts/generate-versions.ts && tsc"
4938
```
@@ -53,54 +42,36 @@ Change build to:
5342
### Step 4: Rewrite src/index.ts
5443
**File**: `packages/create-vite-app/src/index.ts`
5544

56-
Structure:
57-
```ts
58-
#!/usr/bin/env node
59-
import * as p from '@clack/prompts'
60-
import { versions } from './versions.js'
61-
// ... fs utilities
62-
63-
async function main() {
64-
p.intro('Create Fastify + Vite App')
65-
66-
// 1. Get project name (with CLI arg fallback)
67-
const projectName = await p.text({...})
45+
Features:
46+
- Interactive project name prompt using @clack/prompts
47+
- Copies template files from bundled `templates/react-spa`
48+
- Transforms package.json (resolves versions, updates name)
49+
- Auto-detects package manager and installs dependencies
50+
- Shows spinner during operations
6851

69-
// 2. Copy template files from examples/react-vanilla-spa
70-
// - Skip: node_modules, dist, *.test.js
71-
// - Transform package.json with resolved versions
72-
73-
// 3. Detect package manager (npm/pnpm/yarn/bun)
74-
// 4. Run install with spinner
75-
76-
p.outro('Done! Run: cd <project> && npm run dev')
77-
}
78-
```
79-
80-
### Step 5: Add template copying logic
81-
**File**: `packages/create-vite-app/src/index.ts`
52+
### Step 5: Create .gitignore
53+
**File**: `packages/create-vite-app/.gitignore`
8254

83-
Key functions:
84-
- `copyTemplate(source, dest)` - recursively copy, skip ignored files
85-
- `transformPackageJson(content, projectName, versions)` - replace workspace:/catalog: refs
86-
- `detectPackageManager()` - check lockfiles or npm_config_user_agent
87-
- `installDependencies(pm, cwd)` - spawn install process
55+
Ignores build-time generated files:
56+
- `src/versions.json`
57+
- `templates/`
8858

8959
---
9060

91-
## Files to Modify/Create
61+
## Files Modified/Created
9262

9363
| File | Action |
9464
|------|--------|
95-
| `packages/create-vite-app/package.json` | Modify - add deps, update build script |
96-
| `packages/create-vite-app/scripts/generate-versions.ts` | Create |
97-
| `packages/create-vite-app/src/versions.ts` | Generated (gitignored) |
98-
| `packages/create-vite-app/src/index.ts` | Rewrite |
99-
| `packages/create-vite-app/.gitignore` | Create - ignore src/versions.ts |
65+
| `packages/create-vite-app/package.json` | Modified - added deps, updated build script |
66+
| `packages/create-vite-app/scripts/generate-versions.ts` | Created |
67+
| `packages/create-vite-app/src/versions.json` | Generated (gitignored) |
68+
| `packages/create-vite-app/src/index.ts` | Rewritten |
69+
| `packages/create-vite-app/.gitignore` | Created |
70+
| `packages/create-vite-app/templates/` | Generated (gitignored) |
10071

10172
---
10273

103-
## Template Files Copied (from examples/react-vanilla-spa/)
74+
## Generated Project Structure
10475

10576
```
10677
project-name/
@@ -109,7 +80,7 @@ project-name/
10980
│ ├── base.jsx
11081
│ ├── index.html
11182
│ └── mount.js
112-
├── package.json (transformed)
83+
├── package.json (transformed with resolved versions)
11384
├── server.js
11485
└── vite.config.js
11586
```

packages/create-vite-app/package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
],
1414
"scripts": {
1515
"dev": "node src/index.ts",
16-
"build": "tsc",
16+
"build": "node scripts/generate-versions.ts && tsc",
1717
"prepublishOnly": "pnpm build",
1818
"test": "node --test"
1919
},
@@ -37,8 +37,12 @@
3737
"engines": {
3838
"node": ">=22.18.0"
3939
},
40+
"dependencies": {
41+
"@clack/prompts": "^0.11.0"
42+
},
4043
"devDependencies": {
4144
"typescript": "catalog:",
42-
"@types/node": "catalog:"
45+
"@types/node": "catalog:",
46+
"yaml": "^2.8.2"
4347
}
4448
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs'
2+
import { join } from 'node:path'
3+
import { parse } from 'yaml'
4+
5+
const rootDir = join(import.meta.dirname, '..', '..', '..')
6+
const pkgDir = join(import.meta.dirname, '..')
7+
8+
// Read pnpm-workspace.yaml
9+
const workspaceYaml = readFileSync(join(rootDir, 'pnpm-workspace.yaml'), 'utf-8')
10+
const workspace = parse(workspaceYaml) as {
11+
catalog: Record<string, string>
12+
catalogs: Record<string, Record<string, string>>
13+
}
14+
15+
// Read @fastify/vite version from its package.json
16+
const fastifyVitePkg = JSON.parse(
17+
readFileSync(join(rootDir, 'packages', 'fastify-vite', 'package.json'), 'utf-8')
18+
)
19+
20+
// Build the versions object
21+
const versions: Record<string, string> = {
22+
'@fastify/vite': `^${fastifyVitePkg.version}`,
23+
fastify: workspace.catalog.fastify,
24+
vite: workspace.catalog.vite,
25+
react: workspace.catalogs.react.react,
26+
'react-dom': workspace.catalogs.react['react-dom'],
27+
'@vitejs/plugin-react': workspace.catalogs.react['@vitejs/plugin-react'],
28+
}
29+
30+
// Generate the versions.json file
31+
const versionsPath = join(pkgDir, 'src', 'versions.json')
32+
writeFileSync(versionsPath, JSON.stringify(versions, null, 2) + '\n')
33+
console.log('Generated src/versions.json with versions:', versions)
34+
35+
// Copy template files from examples/react-vanilla-spa to templates/react-spa
36+
const SKIP_PATTERNS = ['node_modules', 'dist', '.test.js', '.test.ts']
37+
38+
function shouldSkip(name: string): boolean {
39+
return SKIP_PATTERNS.some((pattern) => name.includes(pattern))
40+
}
41+
42+
function copyTemplate(src: string, dest: string): void {
43+
const entries = readdirSync(src, { withFileTypes: true })
44+
45+
for (const entry of entries) {
46+
if (shouldSkip(entry.name)) continue
47+
48+
const srcPath = join(src, entry.name)
49+
const destPath = join(dest, entry.name)
50+
51+
if (entry.isDirectory()) {
52+
mkdirSync(destPath, { recursive: true })
53+
copyTemplate(srcPath, destPath)
54+
} else {
55+
cpSync(srcPath, destPath)
56+
}
57+
}
58+
}
59+
60+
const templateSrc = join(rootDir, 'examples', 'react-vanilla-spa')
61+
const templateDest = join(pkgDir, 'templates', 'react-spa')
62+
63+
// Clean and recreate templates directory
64+
if (existsSync(join(pkgDir, 'templates'))) {
65+
rmSync(join(pkgDir, 'templates'), { recursive: true })
66+
}
67+
mkdirSync(templateDest, { recursive: true })
68+
69+
copyTemplate(templateSrc, templateDest)
70+
console.log('Copied template files to templates/react-spa')

0 commit comments

Comments
 (0)