Skip to content

Commit 310fe5c

Browse files
committed
feat: 添加serve脚本
1 parent 65010d9 commit 310fe5c

2 files changed

Lines changed: 208 additions & 9 deletions

File tree

scripts/build.ts

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ interface AppInfo {
2222
name: string
2323
packageName: string
2424
description: string
25+
buildScripts: string[]
2526
}
2627

2728
function getApps(): AppInfo[] {
@@ -36,24 +37,44 @@ function getApps(): AppInfo[] {
3637
const packageJsonPath = path.join(appsDir, entry.name, 'package.json')
3738
if (fs.existsSync(packageJsonPath)) {
3839
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'))
39-
if (pkg.scripts?.build) {
40+
const buildScripts = Object.keys(pkg.scripts || {}).filter(s => s === 'build' || s.startsWith('build:'))
41+
if (buildScripts.length > 0) {
4042
apps.push({
4143
name: entry.name,
4244
packageName: pkg.name,
4345
description: pkg.description || '',
46+
buildScripts,
4447
})
4548
}
4649
}
4750
}
4851
}
4952
}
5053

54+
// Scan docs directory (root level)
55+
const docsDir = path.resolve(rootDir, 'docs')
56+
if (fs.existsSync(docsDir)) {
57+
const packageJsonPath = path.join(docsDir, 'package.json')
58+
if (fs.existsSync(packageJsonPath)) {
59+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'))
60+
const buildScripts = Object.keys(pkg.scripts || {}).filter(s => s === 'build' || s.startsWith('build:'))
61+
if (buildScripts.length > 0) {
62+
apps.push({
63+
name: 'docs',
64+
packageName: pkg.name,
65+
description: pkg.description || '',
66+
buildScripts,
67+
})
68+
}
69+
}
70+
}
71+
5172
return apps
5273
}
5374

54-
async function runBuild(packageName: string): Promise<void> {
75+
async function runBuild(packageName: string, script: string): Promise<void> {
5576
return new Promise((resolve, reject) => {
56-
childProcess = spawn('pnpm', ['--filter', packageName, 'run', 'build'], {
77+
childProcess = spawn('pnpm', ['--filter', packageName, 'run', script], {
5778
stdio: 'inherit',
5879
cwd: rootDir,
5980
})
@@ -75,6 +96,24 @@ async function runBuild(packageName: string): Promise<void> {
7596
})
7697
}
7798

99+
async function selectBuildScript(app: AppInfo): Promise<string> {
100+
if (app.buildScripts.length === 1) {
101+
return app.buildScripts[0]
102+
}
103+
104+
const script = await p.select({
105+
message: `Select build script for "${app.name}":`,
106+
options: app.buildScripts.map(s => ({ value: s, label: s })),
107+
})
108+
109+
if (p.isCancel(script)) {
110+
p.cancel('Operation cancelled')
111+
process.exit(0)
112+
}
113+
114+
return script as string
115+
}
116+
78117
async function main() {
79118
p.intro('Select apps to build')
80119

@@ -87,7 +126,8 @@ async function main() {
87126

88127
if (apps.length === 1) {
89128
p.log.info(`Only one app found: ${apps[0].name}`)
90-
await runBuild(apps[0].packageName)
129+
const script = await selectBuildScript(apps[0])
130+
await runBuild(apps[0].packageName, script)
91131
p.outro('Build complete!')
92132
return
93133
}
@@ -109,13 +149,13 @@ async function main() {
109149
process.exit(0)
110150
}
111151

112-
const selectedApps = selected as string[]
113-
114-
p.log.info(`Building ${selectedApps.length} app(s)...`)
152+
const selectedPackageNames = selected as string[]
153+
const selectedApps = selectedPackageNames.map(pkg => apps.find(a => a.packageName === pkg)!)
115154

116155
for (const app of selectedApps) {
117-
p.log.info(`Building ${app}...`)
118-
await runBuild(app)
156+
const script = await selectBuildScript(app)
157+
p.log.info(`Building "${app.name}" with script "${script}"...`)
158+
await runBuild(app.packageName, script)
119159
}
120160

121161
p.outro('Build complete!')

scripts/serve.ts

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
#!/usr/bin/env node
2+
3+
import { spawn } from 'node:child_process'
4+
import fs from 'node:fs'
5+
import path from 'node:path'
6+
import process from 'node:process'
7+
import { fileURLToPath } from 'node:url'
8+
import * as p from '@clack/prompts'
9+
10+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
11+
const rootDir = path.resolve(__dirname, '..')
12+
13+
let childProcess: ReturnType<typeof spawn> | null = null
14+
15+
process.on('SIGINT', () => {
16+
if (childProcess) {
17+
childProcess.kill('SIGINT')
18+
}
19+
})
20+
21+
interface AppInfo {
22+
name: string
23+
packageName: string
24+
description: string
25+
serveScripts: string[]
26+
}
27+
28+
function getApps(): AppInfo[] {
29+
const apps: AppInfo[] = []
30+
31+
// Scan apps directory (subdirectories)
32+
const appsDir = path.resolve(rootDir, 'apps')
33+
if (fs.existsSync(appsDir)) {
34+
const entries = fs.readdirSync(appsDir, { withFileTypes: true })
35+
for (const entry of entries) {
36+
if (entry.isDirectory()) {
37+
const packageJsonPath = path.join(appsDir, entry.name, 'package.json')
38+
if (fs.existsSync(packageJsonPath)) {
39+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'))
40+
const serveScripts = Object.keys(pkg.scripts || {}).filter(s => s === 'serve' || s.startsWith('serve:'))
41+
if (serveScripts.length > 0) {
42+
apps.push({
43+
name: entry.name,
44+
packageName: pkg.name,
45+
description: pkg.description || '',
46+
serveScripts,
47+
})
48+
}
49+
}
50+
}
51+
}
52+
}
53+
54+
// Scan docs directory (root level)
55+
const docsDir = path.resolve(rootDir, 'docs')
56+
if (fs.existsSync(docsDir)) {
57+
const packageJsonPath = path.join(docsDir, 'package.json')
58+
if (fs.existsSync(packageJsonPath)) {
59+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'))
60+
const serveScripts = Object.keys(pkg.scripts || {}).filter(s => s === 'serve' || s.startsWith('serve:'))
61+
if (serveScripts.length > 0) {
62+
apps.push({
63+
name: 'docs',
64+
packageName: pkg.name,
65+
description: pkg.description || '',
66+
serveScripts,
67+
})
68+
}
69+
}
70+
}
71+
72+
return apps
73+
}
74+
75+
async function runServe(packageName: string, script: string): Promise<void> {
76+
return new Promise((resolve, reject) => {
77+
childProcess = spawn('pnpm', ['--filter', packageName, 'run', script], {
78+
stdio: 'inherit',
79+
cwd: rootDir,
80+
})
81+
82+
childProcess.on('close', (code) => {
83+
childProcess = null
84+
if (code === 0 || code === null) {
85+
resolve()
86+
}
87+
else {
88+
reject(new Error(`Process exited with code ${code}`))
89+
}
90+
})
91+
92+
childProcess.on('error', (err) => {
93+
childProcess = null
94+
reject(err)
95+
})
96+
})
97+
}
98+
99+
async function selectServeScript(app: AppInfo): Promise<string> {
100+
if (app.serveScripts.length === 1) {
101+
return app.serveScripts[0]
102+
}
103+
104+
const script = await p.select({
105+
message: `Select serve script for "${app.name}":`,
106+
options: app.serveScripts.map(s => ({ value: s, label: s })),
107+
})
108+
109+
if (p.isCancel(script)) {
110+
p.cancel('Operation cancelled')
111+
process.exit(0)
112+
}
113+
114+
return script as string
115+
}
116+
117+
async function main() {
118+
p.intro('Select an app to serve')
119+
120+
const apps = getApps()
121+
122+
if (apps.length === 0) {
123+
p.log.error('No apps found with serve script')
124+
process.exit(1)
125+
}
126+
127+
if (apps.length === 1) {
128+
p.log.info(`Only one app found: ${apps[0].name}`)
129+
const script = await selectServeScript(apps[0])
130+
await runServe(apps[0].packageName, script)
131+
return
132+
}
133+
134+
const choices = apps.map(app => ({
135+
value: app.packageName,
136+
label: app.name,
137+
hint: app.description,
138+
}))
139+
140+
const selected = await p.select({
141+
message: 'Which app do you want to serve?',
142+
options: choices,
143+
})
144+
145+
if (p.isCancel(selected)) {
146+
p.cancel('Operation cancelled')
147+
process.exit(0)
148+
}
149+
150+
const selectedApp = apps.find(a => a.packageName === selected)!
151+
const script = await selectServeScript(selectedApp)
152+
p.log.info(`Serving "${selectedApp.name}" with script "${script}"...`)
153+
await runServe(selectedApp.packageName, script)
154+
}
155+
156+
main().catch((err) => {
157+
p.log.error(err.message)
158+
process.exit(1)
159+
})

0 commit comments

Comments
 (0)