Files
prompt-optimizer/docs/workspace-trpc/experience.md
linshen d1f6c62390 feat: 重构UI层状态持久化架构,增强Electron API交互与Prompt服务
- 导出偏好设置服务类型和实现,增强服务可用性。
- 实现`ElectronPreferenceServiceProxy`和`PreferenceService`,提供偏好设置管理功能。
- 更新组件,使用偏好设置服务替代原有存储逻辑,提升代码可维护性和一致性。
- 集成偏好设置服务的IPC处理逻辑,确保主进程正确处理相关请求。
- 新增重构UI层状态持久化架构任务,目标是将UI层对`useStorage`的直接依赖替换为`PreferenceService`。
- 优化IPC通信,新增对流式处理的支持,增强Prompt服务功能。
- 集成Prompt服务的IPC处理逻辑,并新增成功和错误响应辅助函数,简化IPC处理逻辑,提升代码可读性和一致性;同时优化多个IPC处理函数,确保在发生错误时能够统一返回错误信息,增强错误管理。
- 新增对`iteratePrompt`、`testPrompt`、`getHistory`、`getIterationChain`等方法的支持,暴露Prompt服务接口,方便前端调用,扩展前端与主进程的交互能力。
- 删除不再使用的Markdown输出规则和AI开发工作流程文档,提升项目的可维护性和文档的清晰度。
2025-06-29 17:02:33 +08:00

131 lines
7.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 开发经验记录
记录开发过程中的重要经验和最佳实践。
## 🔧 构建与依赖管理 (Monorepo & Vite)
**经验**: 在 pnpm workspace (monorepo) 中,当一个包(如`@core`需要同时服务于前端Vite构建的`@ui`和后端Node.js/Electron处理导出和依赖关系需要特别小心以避免构建冲突。
**场景**:
- 一个`@core`其中一部分代码如tRPC路由仅用于后端另一部分是通用代码。
- 一个`@ui`使用Vite构建依赖`@core`包。
- 一个`@desktop`使用Electron也依赖`@core`包,并需要使用其仅后端的代码。
**问题**:
1. 如果`@core`包在其主入口 (`index.ts`) 导出了仅后端的代码,会导致前端应用打包进不必要的服务器依赖(如`@trpc/server`)。
2. 如果为了解决问题1使用`package.json``exports`映射为后端代码创建单独入口可能会破坏Vite的依赖解析机制导致`@ui`包构建失败。
3. 如果在`@ui`的Vite配置中将`@core`包设为`external`,会增加最终应用的配置复杂性,使其无法"开箱即用"。
**最佳实践 / 解决方案**:
1. **组件库自包含 (Batteries Included)**: 在 `@ui` 包的 `vite.config.ts` 中,**移除**内部依赖(如 `@core`)的 `external` 配置。让UI库成为一个完整的、内置所有必要依赖的自包含产品。
2. **核心包多入口构建**: 在 `@core` 包中,使用 `tsup` 等工具配置**多入口点**构建。一个入口是提供给前端和大部分后端的公共API (`index.ts`),另一个是仅用于特定后端的专门文件(如 `router.ts`)。
3. **分离导出与实现 (公共API vs 内部路径)**:
- **不要**在 `package.json` 中为仅后端的代码创建复杂的 `exports` 映射。保持主 `exports` 干净、简单只指向公共API。
- 在需要使用仅后端代码的地方(如 `desktop/main.js`),直接通过**相对文件路径**从 `dist` 目录中 `require` 编译后的文件。
**代码示例**:
- `packages/core/package.json` (scripts):
`"build": "tsup src/index.ts src/services/trpc/router.ts --format cjs,esm --dts"`
- `packages/desktop/main.js` (import):
`const { createAppRouter } = require('@prompt-optimizer/core/dist/services/trpc/router.cjs');`
**结论**: 这种"公共API + 内部路径"的策略优雅地解决了前后端对同一个包的不同需求保证了Vite构建的顺利进行也维持了后端功能的可用性。
**核心原则**: 必须同时满足现代前端构建工具如Vite和后端环境Node.js的模块解析规则。核心是遵守Node.js的`exports`封装性并以此为基础解决Vite的兼容问题。
**遇到的问题演进**:
1. **前端加载后端代码**: `@core`包的`index.ts`导出了仅服务器端的代码,导致浏览器报错。
2. **Vite构建失败**: 为解决问题1尝试使用`exports`为后端代码创建单独入口但这种多入口配置导致Vite无法解析依赖。
3. **Node.js路径未导出 (ERR_PACKAGE_PATH_NOT_EXPORTED)**: 为解决问题2尝试让后端直接引用内部文件路径但这违反了Node.js的模块封装规则因为`exports`字段存在时,所有访问必须经过它的允许。
**最终的最佳实践 (The Standard Way)**:
1. **组件库自包含 (Batteries Included)**:
-`@ui` 包的 `vite.config.ts` 中,**移除**内部依赖(如 `@core`)的 `external` 配置。让UI库成为一个完整的、内置所有必要依赖的自包含产品。这是解决问题的起点。
2. **在核心包中明确声明所有导出**:
-`@core` 包的 `package.json` 中,使用 `exports` 字段**明确声明所有**需要被外部访问的路径,无论是给前端还是后端使用。
- 使用 `tsup` 等工具进行多入口点构建,确保 `exports` 中声明的每个路径都有对应的编译产物。
3. **所有消费者都使用标准路径**:
- 无论是前端还是后端,都应该通过 `exports` 中声明的标准路径来导入模块 (e.g., `'@prompt-optimizer/core'``'@prompt-optimizer/core/trpc-router'`)。
- **禁止**任何包从另一个包的内部文件路径(如 `dist/...`)进行导入。
**代码示例 (最终正确配置)**:
- `packages/core/package.json`:
```json
"exports": {
".": { "import": "./dist/index.js", "require": "./dist/index.cjs" },
"./trpc-router": { "import": "./dist/services/trpc/router.js", "require": "./dist/services/trpc/router.cjs" }
},
"scripts": {
"build": "tsup src/index.ts src/services/trpc/router.ts --format cjs,esm --dts"
}
```
- `packages/desktop/main.js`:
`const { createAppRouter } = require('@prompt-optimizer/core/trpc-router');`
**结论**: 这个标准化的解决方案保证了 `@core` 包的强封装性同时为不同环境的消费者提供了清晰、稳定、唯一的访问接口。如果在此基础上Vite仍然构建失败那么下一步应该去调整Vite自身的配置如 `resolve.alias` 或 `optimizeDeps.exclude`),而不是破坏包的封装规则。
## 🔧 技术经验
### 架构设计
- [经验描述] - [适用场景] - [记录日期]
### 错误处理
- [错误类型] - [解决方案] - [预防措施] - [记录日期]
### 性能优化
- [优化点] - [优化方法] - [效果] - [记录日期]
### 测试实践
- [测试类型] - [最佳实践] - [工具推荐] - [记录日期]
## 🛠️ 工具配置
### 开发工具
- [工具名称] - [配置要点] - [使用技巧] - [记录日期]
### 调试技巧
- [问题类型] - [调试方法] - [工具使用] - [记录日期]
## 📚 学习资源
### 有用文档
- [文档标题] - [链接] - [要点总结] - [记录日期]
### 代码示例
- [功能描述] - [代码片段或文件位置] - [使用场景] - [记录日期]
## 🚫 避坑指南
### 常见错误
- [错误描述] - [原因分析] - [避免方法] - [记录日期]
### 设计陷阱
- [设计问题] - [问题后果] - [正确做法] - [记录日期]
## 🔄 流程改进
### 工作流优化
- **经验**: 在Monorepo中设计开发命令时要避免并行进程操作同一目录导致的"赛跑条件"。
- **场景**: 使用`concurrently`并行执行多个任务其中一个任务是Vite开发服务器(`vite dev`),另一个是其依赖库的监视构建任务(`vite build --watch`)。
- **问题**: `vite dev`在启动时需要读取依赖库(如`@ui`)的构建产物(如`dist/style.css`),而`vite build --watch`在同一时间可能正在清理或重写该`dist`目录,导致文件读取失败,引发样式丢失等问题。
- **最佳实践**:
1. **信任Vite开发服务器**在开发环境下应该最大限度地利用Vite开发服务器的内置能力。它能够直接处理对工作区内其他包workspace-local packages的依赖并从它们的**源文件**`src`)进行实时编译和热更新。
2. **避免预构建和监视**:因此,在启动主应用的开发服务器时,**不应该**同时运行其依赖库的`build --watch`任务。
3. **简化并行命令**: 开发命令应只包含主应用的开发服务器(如`vite dev`)和其他必要的后端服务(如`electron .`。让单个Vite实例全权负责所有前端代码的编译。
- **示例 (package.json)**:
- **错误示范**: `concurrently "pnpm -F @ui watch" "pnpm -F @web dev"`
- **正确示范**: `concurrently "pnpm -F @web dev" "pnpm -F @desktop dev"` (假设web负责所有UIdesktop是后端)
- **记录日期**: 2024-07-28
### 文档管理
- [管理经验] - [工具使用] - [效率提升] - [记录日期]
---
## 📝 使用说明
1. **及时记录** - 遇到重要经验立即记录
2. **分类整理** - 按照上述分类组织内容
3. **定期回顾** - 每周回顾一次,提取可复用经验
4. **归档整理** - 任务完成时将相关经验归档到archives