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

7.8 KiB
Raw Permalink Blame History

开发经验记录

记录开发过程中的重要经验和最佳实践。

🔧 构建与依赖管理 (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.jsonexports映射为后端代码创建单独入口可能会破坏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:
    "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.aliasoptimizeDeps.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