refactor: simplify compile.ts to single-target and add per-platform compile scripts

- Rewrite compile.ts from 112 to 66 lines: single target with auto-detect host, remove multi-target batch logic
- Add compile:linux/mac/win scripts to server, root, and turbo configs
- Wire desktop dist:* to depend on matching server compile:* (avoid unnecessary cross-platform compilation)
- Update AGENTS.md docs across root, server, and desktop
This commit is contained in:
2026-02-08 22:25:30 +08:00
parent dac6bb1643
commit e171db8196
9 changed files with 87 additions and 99 deletions

View File

@@ -1,111 +1,66 @@
import { rm } from 'node:fs/promises'
import path from 'node:path'
import process from 'node:process'
const ALL_TARGETS = [
const ENTRYPOINT = '.output/server/index.mjs'
const OUTDIR = 'out'
const VALID_TARGETS = [
'bun-windows-x64',
'bun-darwin-arm64',
'bun-darwin-x64',
'bun-linux-x64',
'bun-linux-arm64',
] as const
type BunTarget = (typeof ALL_TARGETS)[number]
type Target = (typeof VALID_TARGETS)[number]
const ENTRYPOINT = '.output/server/index.mjs'
const OUTDIR = 'out'
const OUTFILE_BASE = 'server'
const DEFAULT_TARGETS: BunTarget[] = [
'bun-windows-x64',
'bun-darwin-arm64',
'bun-linux-x64',
]
const suffixFor = (target: BunTarget) => target.replace('bun-', '')
const isTarget = (value: string): value is BunTarget =>
(ALL_TARGETS as readonly string[]).includes(value)
const parseTargets = (): BunTarget[] => {
const args = process.argv.slice(2)
const targets: string[] = []
for (let i = 0; i < args.length; i++) {
const arg = args[i]
const next = args[i + 1]
if (arg === '--target' && next) {
targets.push(next)
i++
} else if (arg === '--targets' && next) {
targets.push(...next.split(','))
i++
}
}
if (targets.length === 0) return DEFAULT_TARGETS
const invalid = targets.filter((t) => !isTarget(t))
if (invalid.length) {
throw new Error(
`Unknown target(s): ${invalid.join(', ')}\nAllowed: ${ALL_TARGETS.join(', ')}`,
)
}
return targets as BunTarget[]
const HOST_MAP: Record<string, Target> = {
'win32-x64': 'bun-windows-x64',
'darwin-arm64': 'bun-darwin-arm64',
'linux-x64': 'bun-linux-x64',
'linux-arm64': 'bun-linux-arm64',
}
const buildOne = async (target: BunTarget) => {
const suffix = suffixFor(target)
const outfile = `${OUTFILE_BASE}-${suffix}`
const resolveTarget = (): Target => {
const idx = process.argv.indexOf('--target')
if (idx !== -1) {
const value = process.argv[idx + 1]
if (!value || !VALID_TARGETS.includes(value as Target)) {
throw new Error(
`Invalid target: ${value}\nAllowed: ${VALID_TARGETS.join(', ')}`,
)
}
return value as Target
}
const key = `${process.platform}-${process.arch}`
const target = HOST_MAP[key]
if (!target) {
throw new Error(`Unsupported host: ${key}`)
}
return target
}
const main = async () => {
const target = resolveTarget()
const suffix = target.replace('bun-', '')
const outfile = `server-${suffix}`
await rm(OUTDIR, { recursive: true, force: true })
const result = await Bun.build({
entrypoints: [ENTRYPOINT],
outdir: OUTDIR,
compile: {
outfile,
target,
},
compile: { outfile, target },
})
if (!result.success) {
throw new Error(
`Build failed for ${target}:\n${result.logs.map(String).join('\n')}`,
)
throw new Error(result.logs.map(String).join('\n'))
}
return {
target,
outputs: result.outputs.map((o) => path.relative('.', o.path)),
}
}
const main = async () => {
const targets = parseTargets()
await rm(OUTDIR, { recursive: true, force: true })
console.log(`✓ 已清理输出目录: ${OUTDIR}`)
// Bun cross-compile 不支持真正并行,逐目标串行构建
const results: Awaited<ReturnType<typeof buildOne>>[] = []
for (const target of targets) {
const start = Date.now()
process.stdout.write(`🔨 构建 ${target}... `)
const result = await buildOne(target)
results.push(result)
console.log(`完成 (${Date.now() - start}ms)`)
}
console.log('\n📦 构建完成:')
for (const r of results) {
console.log(` ${r.target}:`)
for (const p of r.outputs) {
console.log(` - ${p}`)
}
}
console.log(`${target}${OUTDIR}/${outfile}`)
}
main().catch((err) => {
console.error('\n❌ 构建失败:')
console.error(err instanceof Error ? err.message : err)
console.error('❌', err instanceof Error ? err.message : err)
process.exit(1)
})