- 使用 Effect 模块重构构建脚本,引入类型安全的配置与错误处理,实现并行构建多平台目标并输出结构化构建摘要。 - 添加 effect 库及其依赖项以支持函数式编程特性 - 添加 effect 依赖以支持函数式响应式编程特性
154 lines
4.0 KiB
TypeScript
154 lines
4.0 KiB
TypeScript
import { $ } from 'bun'
|
|
import { Console, Effect } from 'effect'
|
|
|
|
// ============================================================================
|
|
// Domain Models
|
|
// ============================================================================
|
|
|
|
const targetMap = {
|
|
'bun-windows-x64': 'x86_64-pc-windows-msvc',
|
|
'bun-darwin-arm64': 'aarch64-apple-darwin',
|
|
'bun-darwin-x64': 'x86_64-apple-darwin',
|
|
'bun-linux-x64': 'x86_64-unknown-linux-gnu',
|
|
'bun-linux-arm64': 'aarch64-unknown-linux-gnu',
|
|
} as const
|
|
|
|
type BunTarget = keyof typeof targetMap
|
|
|
|
type BuildConfig = Readonly<{
|
|
entrypoint: string
|
|
outputDir: string
|
|
targets: ReadonlyArray<BunTarget>
|
|
}>
|
|
|
|
type BuildResult = Readonly<{
|
|
target: BunTarget
|
|
outputs: ReadonlyArray<string>
|
|
}>
|
|
|
|
// ============================================================================
|
|
// Configuration
|
|
// ============================================================================
|
|
|
|
const defaultConfig: BuildConfig = {
|
|
entrypoint: './.output/server/index.mjs',
|
|
outputDir: './out',
|
|
targets: ['bun-windows-x64', 'bun-darwin-arm64', 'bun-linux-x64'],
|
|
}
|
|
|
|
// ============================================================================
|
|
// Effects
|
|
// ============================================================================
|
|
|
|
/**
|
|
* 清理输出目录
|
|
*/
|
|
const cleanOutputDir = (dir: string) =>
|
|
Effect.tryPromise({
|
|
try: async () => {
|
|
await $`rm -rf ${dir}`
|
|
return undefined
|
|
},
|
|
catch: (error: unknown) => ({
|
|
_tag: 'CleanError' as const,
|
|
message: `无法清理目录 ${dir}`,
|
|
cause: error,
|
|
}),
|
|
}).pipe(Effect.tap(() => Console.log(`✓ 已清理输出目录: ${dir}`)))
|
|
|
|
/**
|
|
* 为单个目标平台构建
|
|
*/
|
|
const buildForTarget = (
|
|
config: BuildConfig,
|
|
target: BunTarget,
|
|
): Effect.Effect<
|
|
BuildResult,
|
|
{ _tag: 'BuildError'; target: BunTarget; message: string; cause: unknown }
|
|
> =>
|
|
Effect.gen(function* () {
|
|
yield* Console.log(`🔨 开始构建: ${target}`)
|
|
|
|
const output = yield* Effect.tryPromise({
|
|
try: () =>
|
|
Bun.build({
|
|
entrypoints: [config.entrypoint],
|
|
compile: {
|
|
outfile: `server-${targetMap[target]}`,
|
|
target: target,
|
|
},
|
|
outdir: config.outputDir,
|
|
}),
|
|
catch: (error: unknown) => ({
|
|
_tag: 'BuildError' as const,
|
|
target,
|
|
message: `构建失败: ${target}`,
|
|
cause: error,
|
|
}),
|
|
})
|
|
|
|
const paths = output.outputs.map((item: { path: string }) => item.path)
|
|
|
|
return {
|
|
target,
|
|
outputs: paths,
|
|
} satisfies BuildResult
|
|
})
|
|
|
|
/**
|
|
* 并行构建所有目标平台
|
|
*/
|
|
const buildAllTargets = (config: BuildConfig) => {
|
|
const effects = config.targets.map((target) => buildForTarget(config, target))
|
|
return Effect.all(effects, { concurrency: 'unbounded' })
|
|
}
|
|
|
|
/**
|
|
* 输出构建结果摘要
|
|
*/
|
|
const printBuildSummary = (results: ReadonlyArray<BuildResult>) =>
|
|
Effect.gen(function* () {
|
|
yield* Console.log('\n📦 构建完成:')
|
|
for (const result of results) {
|
|
yield* Console.log(` ${result.target}:`)
|
|
for (const path of result.outputs) {
|
|
yield* Console.log(` - ${path}`)
|
|
}
|
|
}
|
|
})
|
|
|
|
// ============================================================================
|
|
// Main Program
|
|
// ============================================================================
|
|
|
|
const program = Effect.gen(function* () {
|
|
const config = defaultConfig
|
|
|
|
// 1. 清理输出目录
|
|
yield* cleanOutputDir(config.outputDir)
|
|
|
|
// 2. 并行构建所有目标
|
|
const results = yield* buildAllTargets(config)
|
|
|
|
// 3. 输出构建摘要
|
|
yield* printBuildSummary(results)
|
|
|
|
return results
|
|
})
|
|
|
|
// ============================================================================
|
|
// Runner
|
|
// ============================================================================
|
|
|
|
const main = program.pipe(
|
|
Effect.catchAllCause((cause) =>
|
|
Console.error('❌ 构建失败:', cause).pipe(
|
|
Effect.flatMap(() => Effect.fail(cause)),
|
|
),
|
|
),
|
|
)
|
|
|
|
Effect.runPromise(main).catch(() => {
|
|
process.exit(1)
|
|
})
|