refactor: 重构演示应用目录结构与配置文件路径
- 重命名构建配置文件至指定应用目录 - 重命名 drizzle.config.ts 文件至 apps/demo-app/ 目录下 - 添加演示应用的完整包配置,包含构建、开发、数据库管理及依赖项,支持 Tauri 桌面应用开发。 - 重命名 robots.txt 文件至 demo-app 应用目录下 - 重命名 src-tauri/.gitignore 文件为 apps/demo-app/src-tauri/.gitignore - 重命名 AGENTS.md 文件至指定目录路径 - 重命名构建脚本文件以匹配新项目路径结构 - 重命名默认能力配置文件以匹配新项目路径 - 重命名 Cargo.lock 文件以匹配新的项目路径结构 - 重命名 Cargo.toml 文件以正确反映其在项目中的路径位置 - 重命名图标文件以正确匹配新项目路径 - 重命名128x128.png图标文件至demo-app应用目录下 - 重命名图标文件以正确匹配新项目路径 - 重命名图标文件以匹配新项目路径 - 重命名图标文件以正确匹配新项目路径 - 重命名图标文件以匹配新项目路径 - 重命名图标文件以正确反映其在项目中的路径位置 - 重命名图标文件以匹配新项目路径结构 - 重命名图标文件以正确匹配新项目路径 - 重命名图标文件以正确匹配新项目路径 - 重命名图标文件以正确匹配新项目路径 - 重命名图标文件以正确匹配新项目路径 - 重命名图标文件以匹配新项目路径结构 - 重命名图标文件以正确放置在演示应用的资源目录中 - 重命名图标文件以正确匹配新项目路径 - 重命名图标文件以正确匹配新项目路径 - 重命名命令模块文件路径以匹配项目结构 - 重命名文件以正确反映其在项目中的位置 - 重命名主程序文件路径以匹配项目结构 - 重命名 sidecar.rs 文件至 demo-app 项目路径下 - 重命名 tauri.conf.json 文件至指定目录路径 - 重命名错误组件文件以正确反映其在项目中的位置 - 重命名文件 NotFount.tsx 到指定目录路径 - 重命名数据库入口文件路径以适应项目结构调整 - 重命名数据 schema 文件路径以匹配项目结构 - 重命名文件以正确反映其在项目中的位置路径 - 重命名环境配置文件以正确反映其在项目中的位置。 - 重命名文件以正确反映其在项目中的路径位置 - 重命名文件以正确反映其在项目中的位置 - 重命名文件以正确反映其在项目中的路径位置 - 重命名文件以正确反映其在项目中的路径位置 - 重命名工具函数文件以正确反映其在项目中的位置 - 重命名客户端文件以正确反映其在项目中的位置 - 重命名文件以正确反映其在项目中的位置 - 重命名文件路径以正确组织项目结构中的契约文件 - 重命名文件路径以正确反映其在项目中的位置 - 重命名文件以正确反映其在项目中的位置 - 重命名数据库中间件文件以正确反映其在项目中的位置 - 重命名中间件文件路径以匹配项目结构 - 重命名路由文件以正确反映其在项目中的位置 - 重命名文件以正确反映其在项目中的位置。 - 重命名类型文件以正确反映其在项目中的路径位置 - 重命名路由配置文件以匹配项目目录结构 - 重命名根路由文件以正确反映其在项目中的位置 - 重命名RPC路由文件至demo-app应用目录下 - 重命名路由文件路径以匹配项目结构调整 - 重命名路由树生成文件至 demo-app 应用目录下 - 重命名样式文件以正确反映其在项目中的位置 - 添加 TypeScript 配置以扩展 React 项目模板并设置路径别名。 - 重命名 vite.config.ts 文件至 apps/demo-app/ 目录下 - 移除 biome.json 中对 routeTree.gen.ts 文件的排除规则 - 更新依赖版本以统一使用 catalog 依赖管理,提升项目依赖一致性并升级关键包至最新稳定版本。 - 配置安装时的公共提升模式,包含类型包和特定命名空间的包。 - 删除空的 drizzle 目录占位文件 - 将 node 版本更新为最新版本,同时将 bun 和 rust 版本设置为最新。 - 将项目名称更新为 monorepo 并重构脚本与依赖配置以支持工作区结构和统一的 turbo 管理。 - 添加基础 TypeScript 配置文件,启用严格模式并配置模块解析与编译选项以支持现代 JavaScript 特性。 - 添加 Bun 专用的 TypeScript 配置,继承基础配置并引入 Bun 类型定义。 - 添加 tsconfig 包的配置文件并定义基础、Bun 和 React 的配置导出,同时引入 Bun 类型定义作为开发依赖。 - 添加React项目专用的TypeScript配置,指定JSX处理方式并扩展基础配置。 - 删除旧的 TypeScript 配置文件以移除过时的编译选项和路径别名设置。
This commit is contained in:
289
apps/demo-app/build.ts
Normal file
289
apps/demo-app/build.ts
Normal file
@@ -0,0 +1,289 @@
|
||||
import { Schema } from '@effect/schema'
|
||||
import { $ } from 'bun'
|
||||
import { Console, Context, Data, Effect, Layer } from 'effect'
|
||||
|
||||
// ============================================================================
|
||||
// Domain Models & Schema
|
||||
// ============================================================================
|
||||
|
||||
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
|
||||
|
||||
const BunTargetSchema = Schema.Literal(
|
||||
'bun-windows-x64',
|
||||
'bun-darwin-arm64',
|
||||
'bun-darwin-x64',
|
||||
'bun-linux-x64',
|
||||
'bun-linux-arm64',
|
||||
)
|
||||
|
||||
type BunTarget = Schema.Schema.Type<typeof BunTargetSchema>
|
||||
|
||||
const BuildConfigSchema = Schema.Struct({
|
||||
entrypoint: Schema.String.pipe(Schema.nonEmptyString()),
|
||||
outputDir: Schema.String.pipe(Schema.nonEmptyString()),
|
||||
targets: Schema.Array(BunTargetSchema).pipe(Schema.minItems(1)),
|
||||
})
|
||||
|
||||
type BuildConfig = Schema.Schema.Type<typeof BuildConfigSchema>
|
||||
|
||||
const BuildResultSchema = Schema.Struct({
|
||||
target: BunTargetSchema,
|
||||
outputs: Schema.Array(Schema.String),
|
||||
})
|
||||
|
||||
type BuildResult = Schema.Schema.Type<typeof BuildResultSchema>
|
||||
|
||||
// ============================================================================
|
||||
// Error Models (使用 Data.TaggedError)
|
||||
// ============================================================================
|
||||
|
||||
class CleanError extends Data.TaggedError('CleanError')<{
|
||||
readonly dir: string
|
||||
readonly cause: unknown
|
||||
}> {}
|
||||
|
||||
class BuildError extends Data.TaggedError('BuildError')<{
|
||||
readonly target: BunTarget
|
||||
readonly cause: unknown
|
||||
}> {}
|
||||
|
||||
class ConfigError extends Data.TaggedError('ConfigError')<{
|
||||
readonly message: string
|
||||
readonly cause: unknown
|
||||
}> {}
|
||||
|
||||
// ============================================================================
|
||||
// Services
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* 配置服务
|
||||
*/
|
||||
class BuildConfigService extends Context.Tag('BuildConfigService')<
|
||||
BuildConfigService,
|
||||
BuildConfig
|
||||
>() {
|
||||
/**
|
||||
* 从原始数据创建并验证配置
|
||||
*/
|
||||
static fromRaw = (raw: unknown) =>
|
||||
Effect.gen(function* () {
|
||||
const decoded = yield* Schema.decodeUnknown(BuildConfigSchema)(raw)
|
||||
return decoded
|
||||
}).pipe(
|
||||
Effect.catchAll((error) =>
|
||||
Effect.fail(
|
||||
new ConfigError({
|
||||
message: '配置验证失败',
|
||||
cause: error,
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
/**
|
||||
* 默认配置 Layer
|
||||
*/
|
||||
static readonly Live = Layer.effect(
|
||||
BuildConfigService,
|
||||
BuildConfigService.fromRaw({
|
||||
entrypoint: '.output/server/index.mjs',
|
||||
// outputDir: 'out',
|
||||
outputDir: 'src-tauri/binaries',
|
||||
targets: ['bun-windows-x64', 'bun-darwin-arm64', 'bun-linux-x64'],
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件系统服务
|
||||
*/
|
||||
class FileSystemService extends Context.Tag('FileSystemService')<
|
||||
FileSystemService,
|
||||
{
|
||||
readonly cleanDir: (dir: string) => Effect.Effect<void, CleanError>
|
||||
}
|
||||
>() {
|
||||
static readonly Live = Layer.succeed(FileSystemService, {
|
||||
cleanDir: (dir: string) =>
|
||||
Effect.tryPromise({
|
||||
try: async () => {
|
||||
await $`rm -rf ${dir}`
|
||||
},
|
||||
catch: (cause: unknown) =>
|
||||
new CleanError({
|
||||
dir,
|
||||
cause,
|
||||
}),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建服务
|
||||
*/
|
||||
class BuildService extends Context.Tag('BuildService')<
|
||||
BuildService,
|
||||
{
|
||||
readonly buildForTarget: (
|
||||
config: BuildConfig,
|
||||
target: BunTarget,
|
||||
) => Effect.Effect<BuildResult, BuildError>
|
||||
readonly buildAll: (
|
||||
config: BuildConfig,
|
||||
) => Effect.Effect<ReadonlyArray<BuildResult>, BuildError>
|
||||
}
|
||||
>() {
|
||||
static readonly Live = Layer.succeed(BuildService, {
|
||||
buildForTarget: (config: BuildConfig, target: BunTarget) =>
|
||||
Effect.gen(function* () {
|
||||
yield* Console.log(`🔨 开始构建: ${target}`)
|
||||
|
||||
const output = yield* Effect.tryPromise({
|
||||
try: () =>
|
||||
Bun.build({
|
||||
entrypoints: [config.entrypoint],
|
||||
compile: {
|
||||
outfile: `app-${targetMap[target]}`,
|
||||
target: target,
|
||||
},
|
||||
outdir: config.outputDir,
|
||||
}),
|
||||
catch: (cause: unknown) =>
|
||||
new BuildError({
|
||||
target,
|
||||
cause,
|
||||
}),
|
||||
})
|
||||
|
||||
const paths = output.outputs.map((item: { path: string }) => item.path)
|
||||
|
||||
return {
|
||||
target,
|
||||
outputs: paths,
|
||||
} satisfies BuildResult
|
||||
}),
|
||||
|
||||
buildAll: (config: BuildConfig) =>
|
||||
Effect.gen(function* () {
|
||||
const effects = config.targets.map((target) =>
|
||||
Effect.gen(function* () {
|
||||
yield* Console.log(`🔨 开始构建: ${target}`)
|
||||
|
||||
const output = yield* Effect.tryPromise({
|
||||
try: () =>
|
||||
Bun.build({
|
||||
entrypoints: [config.entrypoint],
|
||||
compile: {
|
||||
outfile: `app-${targetMap[target]}`,
|
||||
target: target,
|
||||
},
|
||||
outdir: config.outputDir,
|
||||
}),
|
||||
catch: (cause: unknown) =>
|
||||
new BuildError({
|
||||
target,
|
||||
cause,
|
||||
}),
|
||||
})
|
||||
|
||||
const paths = output.outputs.map(
|
||||
(item: { path: string }) => item.path,
|
||||
)
|
||||
|
||||
return {
|
||||
target,
|
||||
outputs: paths,
|
||||
} satisfies BuildResult
|
||||
}),
|
||||
)
|
||||
return yield* Effect.all(effects, { concurrency: 'unbounded' })
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 报告服务
|
||||
*/
|
||||
class ReporterService extends Context.Tag('ReporterService')<
|
||||
ReporterService,
|
||||
{
|
||||
readonly printSummary: (
|
||||
results: ReadonlyArray<BuildResult>,
|
||||
) => Effect.Effect<void>
|
||||
}
|
||||
>() {
|
||||
static readonly Live = Layer.succeed(ReporterService, {
|
||||
printSummary: (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 = yield* BuildConfigService
|
||||
const fs = yield* FileSystemService
|
||||
const builder = yield* BuildService
|
||||
const reporter = yield* ReporterService
|
||||
|
||||
// 1. 清理输出目录
|
||||
yield* fs.cleanDir(config.outputDir)
|
||||
yield* Console.log(`✓ 已清理输出目录: ${config.outputDir}`)
|
||||
|
||||
// 2. 并行构建所有目标
|
||||
const results = yield* builder.buildAll(config)
|
||||
|
||||
// 3. 输出构建摘要
|
||||
yield* reporter.printSummary(results)
|
||||
|
||||
return results
|
||||
})
|
||||
|
||||
// ============================================================================
|
||||
// Layer Composition
|
||||
// ============================================================================
|
||||
|
||||
const MainLayer = Layer.mergeAll(
|
||||
BuildConfigService.Live,
|
||||
FileSystemService.Live,
|
||||
BuildService.Live,
|
||||
ReporterService.Live,
|
||||
)
|
||||
|
||||
// ============================================================================
|
||||
// Runner
|
||||
// ============================================================================
|
||||
|
||||
const runnable = program.pipe(
|
||||
Effect.provide(MainLayer),
|
||||
Effect.catchTags({
|
||||
CleanError: (error) =>
|
||||
Console.error(`❌ 清理目录失败: ${error.dir}`, error.cause),
|
||||
BuildError: (error) =>
|
||||
Console.error(`❌ 构建失败 [${error.target}]:`, error.cause),
|
||||
ConfigError: (error) =>
|
||||
Console.error(`❌ 配置错误: ${error.message}`, error.cause),
|
||||
}),
|
||||
Effect.tapErrorCause((cause) => Console.error('❌ 未预期的错误:', cause)),
|
||||
)
|
||||
|
||||
Effect.runPromise(runnable).catch(() => {
|
||||
process.exit(1)
|
||||
})
|
||||
Reference in New Issue
Block a user