Skip to content

Commit f3231cc

Browse files
committed
Use zx
1 parent aaf8f0a commit f3231cc

7 files changed

Lines changed: 83 additions & 140 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"oxlint": "^1.36.0",
1818
"vite": "catalog:",
1919
"vitest": "catalog:",
20-
"zx": "^8.8.5"
20+
"zx": "catalog:"
2121
},
2222
"packageManager": "pnpm@10.26.2+sha512.0e308ff2005fc7410366f154f625f6631ab2b16b1d2e70238444dd6ae9d630a8482d92a451144debc492416896ed16f7b114a86ec68b8404b2443869e68ffda6",
2323
"pnpm": {

packages/create-vite-app/package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,13 @@
3636
"test": "node --test"
3737
},
3838
"dependencies": {
39-
"@clack/prompts": "^0.11.0"
39+
"@clack/prompts": "^0.11.0",
40+
"zx": "catalog:"
4041
},
4142
"devDependencies": {
43+
"@types/fs-extra": "^11.0.4",
4244
"@types/node": "catalog:",
43-
"typescript": "catalog:",
44-
"yaml": "^2.8.2"
45+
"typescript": "catalog:"
4546
},
4647
"engines": {
4748
"node": ">=22.18.0"
Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,14 @@
1-
import { cpSync, existsSync, mkdirSync, readdirSync, rmSync } from 'node:fs'
21
import { join } from 'node:path'
2+
import { fs } from 'zx'
33

44
const rootDir = join(import.meta.dirname, '..', '..', '..')
55
const pkgDir = join(import.meta.dirname, '..')
66

7-
const SKIP_PATTERNS = ['node_modules', 'dist', '.test.js', '.test.ts']
8-
9-
function shouldSkip(name: string): boolean {
10-
return SKIP_PATTERNS.some((pattern) => name.includes(pattern))
11-
}
12-
13-
function copyTemplate(src: string, dest: string): void {
14-
const entries = readdirSync(src, { withFileTypes: true })
15-
16-
for (const entry of entries) {
17-
if (shouldSkip(entry.name)) continue
18-
19-
const srcPath = join(src, entry.name)
20-
const destPath = join(dest, entry.name)
21-
22-
if (entry.isDirectory()) {
23-
mkdirSync(destPath, { recursive: true })
24-
copyTemplate(srcPath, destPath)
25-
} else {
26-
cpSync(srcPath, destPath)
27-
}
28-
}
29-
}
30-
317
const templateSrc = join(rootDir, 'examples', 'react-vanilla-spa')
328
const templateDest = join(pkgDir, 'templates', 'react-spa')
339

34-
// Clean and recreate templates directory
35-
if (existsSync(join(pkgDir, 'templates'))) {
36-
rmSync(join(pkgDir, 'templates'), { recursive: true })
37-
}
38-
mkdirSync(templateDest, { recursive: true })
39-
40-
copyTemplate(templateSrc, templateDest)
10+
fs.removeSync(join(pkgDir, 'templates'))
11+
fs.copySync(templateSrc, templateDest, {
12+
filter: (src) => !src.includes('node_modules') && !src.includes('.test.'),
13+
})
4114
console.log('Copied template files to templates/react-spa')
Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,17 @@
1-
import { readFileSync, writeFileSync } from 'node:fs'
21
import { join } from 'node:path'
3-
import { parse } from 'yaml'
2+
import { fs, YAML } from 'zx'
43

54
const rootDir = join(import.meta.dirname, '..', '..', '..')
65
const pkgDir = join(import.meta.dirname, '..')
76

8-
// Read pnpm-workspace.yaml
9-
const workspaceYaml = readFileSync(join(rootDir, 'pnpm-workspace.yaml'), 'utf-8')
10-
const workspace = parse(workspaceYaml) as {
7+
const workspaceYaml = fs.readFileSync(join(rootDir, 'pnpm-workspace.yaml'), 'utf-8')
8+
const workspace = YAML.parse(workspaceYaml) as {
119
catalog: Record<string, string>
1210
catalogs: Record<string, Record<string, string>>
1311
}
1412

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-
)
13+
const fastifyVitePkg = fs.readJsonSync(join(rootDir, 'packages', 'fastify-vite', 'package.json'))
1914

20-
// Build the versions object
2115
const versions: Record<string, string> = {
2216
'@fastify/vite': `^${fastifyVitePkg.version}`,
2317
fastify: workspace.catalog.fastify,
@@ -27,7 +21,6 @@ const versions: Record<string, string> = {
2721
'@vitejs/plugin-react': workspace.catalogs.react['@vitejs/plugin-react'],
2822
}
2923

30-
// Generate the versions.json file
3124
const versionsPath = join(pkgDir, 'src', 'versions.json')
32-
writeFileSync(versionsPath, JSON.stringify(versions, null, 2) + '\n')
25+
fs.writeJsonSync(versionsPath, versions, { spaces: 2 })
3326
console.log('Generated src/versions.json with versions:', versions)

packages/create-vite-app/src/index.ts

Lines changed: 11 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,18 @@
11
#!/usr/bin/env node
22

3-
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'
43
import { join } from 'node:path'
5-
import { spawn } from 'node:child_process'
64
import * as p from '@clack/prompts'
5+
import { $, fs } from 'zx'
76
import versions from './versions.json' with { type: 'json' }
87

98
const TEMPLATE_DIR = join(import.meta.dirname, '..', 'templates', 'react-spa')
109

11-
const SKIP_PATTERNS = ['node_modules', 'dist', '.test.js', '.test.ts']
12-
13-
function shouldSkip(name: string): boolean {
14-
return SKIP_PATTERNS.some((pattern) => name.includes(pattern))
15-
}
16-
17-
function copyTemplate(src: string, dest: string): void {
18-
const entries = readdirSync(src, { withFileTypes: true })
19-
20-
for (const entry of entries) {
21-
if (shouldSkip(entry.name)) continue
22-
23-
const srcPath = join(src, entry.name)
24-
const destPath = join(dest, entry.name)
25-
26-
if (entry.isDirectory()) {
27-
mkdirSync(destPath, { recursive: true })
28-
copyTemplate(srcPath, destPath)
29-
} else {
30-
cpSync(srcPath, destPath)
31-
}
32-
}
33-
}
34-
3510
function transformPackageJson(projectName: string, destDir: string): void {
3611
const pkgPath = join(destDir, 'package.json')
37-
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'))
12+
const pkg = fs.readJsonSync(pkgPath)
3813

39-
// Update name
4014
pkg.name = projectName
4115

42-
// Replace workspace: and catalog: references with actual versions
4316
for (const depType of ['dependencies', 'devDependencies'] as const) {
4417
if (!pkg[depType]) continue
4518
for (const [name, version] of Object.entries(pkg[depType])) {
@@ -55,14 +28,12 @@ function transformPackageJson(projectName: string, destDir: string): void {
5528
}
5629
}
5730

58-
// Remove private flag for user projects
5931
delete pkg.private
6032

61-
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n')
33+
fs.writeJsonSync(pkgPath, pkg, { spaces: 2 })
6234
}
6335

6436
function detectPackageManager(): 'pnpm' | 'yarn' | 'bun' | 'npm' {
65-
// Check npm_config_user_agent (set when running via package manager)
6637
const userAgent = process.env.npm_config_user_agent
6738
if (userAgent) {
6839
if (userAgent.includes('pnpm')) return 'pnpm'
@@ -72,25 +43,9 @@ function detectPackageManager(): 'pnpm' | 'yarn' | 'bun' | 'npm' {
7243
return 'npm'
7344
}
7445

75-
async function installDependencies(pm: string, cwd: string): Promise<void> {
76-
return new Promise((resolve, reject) => {
77-
const child = spawn(pm, ['install'], {
78-
cwd,
79-
stdio: 'inherit',
80-
shell: process.platform === 'win32',
81-
})
82-
child.on('close', (code) => {
83-
if (code === 0) resolve()
84-
else reject(new Error(`${pm} install failed with code ${code}`))
85-
})
86-
child.on('error', reject)
87-
})
88-
}
89-
9046
async function main(): Promise<void> {
9147
p.intro('Create Fastify + Vite App')
9248

93-
// Get project name from CLI arg or prompt
9449
let projectName = process.argv[2]
9550

9651
if (!projectName) {
@@ -100,7 +55,7 @@ async function main(): Promise<void> {
10055
defaultValue: 'my-fastify-app',
10156
validate: (value) => {
10257
if (!value) return 'Project name is required'
103-
if (existsSync(value)) return `Directory "${value}" already exists`
58+
if (fs.existsSync(value)) return `Directory "${value}" already exists`
10459
},
10560
})
10661

@@ -114,33 +69,33 @@ async function main(): Promise<void> {
11469

11570
const destDir = join(process.cwd(), projectName)
11671

117-
// Check if directory already exists
118-
if (existsSync(destDir)) {
72+
if (fs.existsSync(destDir)) {
11973
p.cancel(`Directory "${projectName}" already exists`)
12074
process.exit(1)
12175
}
12276

123-
// Copy template
12477
const copySpinner = p.spinner()
12578
copySpinner.start('Copying template files...')
12679

12780
try {
128-
mkdirSync(destDir, { recursive: true })
129-
copyTemplate(TEMPLATE_DIR, destDir)
81+
await fs.copy(TEMPLATE_DIR, destDir, {
82+
filter: (src) => !src.includes('node_modules') && !src.includes('.test.'),
83+
})
13084
transformPackageJson(projectName, destDir)
13185
copySpinner.stop('Template files copied')
13286
} catch (error) {
13387
copySpinner.stop('Failed to copy template')
13488
throw error
13589
}
13690

137-
// Install dependencies
13891
const pm = detectPackageManager()
13992
const installSpinner = p.spinner()
14093
installSpinner.start(`Installing dependencies with ${pm}...`)
14194

14295
try {
143-
await installDependencies(pm, destDir)
96+
$.cwd = destDir
97+
$.quiet = true
98+
await $`${pm} install`
14499
installSpinner.stop('Dependencies installed')
145100
} catch {
146101
installSpinner.stop(`Failed to install dependencies. Run "${pm} install" manually.`)

0 commit comments

Comments
 (0)