3213d4c718
- 重构架构:抽离AddCloudSyncServer到扩展类,补全中间层文档对齐 - 修复根路径404与鉴权跳转:新增中间件处理浏览器请求302跳转 - 实现种子数据初始化:添加默认管理员账号自动创建逻辑 - 优化前端代理与构建:新增Vite代理配置与自动构建Target - 补全测试与文档:新增集成测试,更新开发与部署文档
90 lines
7.6 KiB
Markdown
90 lines
7.6 KiB
Markdown
# 研发工单 v1.3.0 - 06:Web 端根路径托管前端
|
||
|
||
> 术语澄清:本文件中"研发工单"指智能体/开发者执行的**编码工作项**,与业务侧的 Todo 待办项无关。详见 [.trae/rules/全局/04-研发工单全流程规范.md](../../../.trae/rules/全局/04-研发工单全流程规范.md)。
|
||
|
||
---
|
||
|
||
## 一、背景与动机
|
||
|
||
根据 [01-项目架构.md](../../../.trae/rules/项目/01-项目架构.md) §3「模式 B:Web 端」端点划分表的定义:
|
||
|
||
| URL 前缀 | 内容 | 来源 |
|
||
|---|---|---|
|
||
| `/`(根路径) | **Hua.Todo.Web 用户前端**(登录后 Todo 列表) | `src/Hua.Todo.Web` 的 `dist/` 构建产物,复制到 `Hua.Todo.Host/wwwroot/` |
|
||
| `/api/*` | 动态 API | DynamicApi |
|
||
| `/admin/*` | 管理后台前端 | `Hua.Todo.Host/wwwroot/admin/`(占位) |
|
||
|
||
**当前代码不符合**:
|
||
|
||
- Host `Program.cs` 没有 `UseStaticFiles()` / `UseDefaultFiles()`;访问 `http://localhost:5173/` 返回 **404**
|
||
- `Hua.Todo.Host.csproj` 没有任何构建 Target 把 `Hua.Todo.Web` 的 `dist/*` 产物拷到 `Hua.Todo.Host/wwwroot/`
|
||
- 开发联调文档缺失:开发时 Vite(:5174)+ Host(:5173)双开怎么跑、端口怎么代理、生产部署怎么构建单文件,都没有书面说明
|
||
|
||
结果:**用户按规则部署"Web 端(Hua.Todo.Host)",会拿到一个只有 API 没有前端页面的半成品服务**。本工单补全模式 B 的生产/开发闭环。
|
||
|
||
## 二、目标 / 范围
|
||
|
||
### 2.1 做什么
|
||
|
||
1. **Host 侧 ASP.NET Core 中间件补齐**:在 `Program.cs` DynamicApi 之前插入 `UseDefaultFiles()` + `UseStaticFiles()`,并保证 SPA 路由(前端内部路由,如 `/settings`)fallback 到 `index.html`(用 `MapFallbackToFile("index.html")`)
|
||
2. **Host csproj 构建 Target**:新增 `npm install`(若 `node_modules` 不存在)+ `npm run build`(Hua.Todo.Web)+ 复制 `dist/**` → `$(OutputPath)/wwwroot/` 的 MSBuild Target,只在构建 Host 时触发(确保 `dotnet publish Hua.Todo.Host` 产出含前端的完整包)
|
||
3. **开发环境联调说明**:在 `docs/manual/08-构建与开发指南.md`(或现有的开发指南对应章节)追加 "模式 B(Web 端)开发双开步骤" 与 "生产发布步骤" 小节
|
||
4. **验收测试**:新增 1 个 Host 集成测试(`WebRootStaticFileTests`),验证 HTTP GET `/` 返回 200 且 body 含 `<title>`/`<div id="app">` 特征
|
||
|
||
### 2.2 不做什么
|
||
|
||
- **不实现 `/admin/*` 管理后台前端**(只有 index.html 占位,v1.2.0 工单 06.1 规划)
|
||
- **不改嵌入式模式 MAUI/Avalonia 的前端托管逻辑**(那边是 `EmbeddedWebServerService` 内自己 UseWebRoot + 复制 wwwroot,与 Host 部署模式解耦)
|
||
- **不改 Hua.Todo.Web 构建逻辑本身**(只调用现成 `npm run build`;不修改 vite.config.ts build.outDir)
|
||
|
||
## 三、前置条件 / 依赖
|
||
|
||
- v1.3.0 工单 05 缺口 D:`CloudSyncEndpointExtensions.cs` 的还原落地(因为本工单需要在 Program.cs 末尾追加 `MapFallbackToFile`,和 `MapCloudSyncProxySettings()` 同时存在于 `Program.cs` 尾部,改动顺序不敏感但建议先落 05 的 D)
|
||
- Node.js + npm 在构建机器可用(作为前置条件,Host csproj Target 不负责安装 Node)
|
||
- 共享文件:`Hua.Todo.Host/Program.cs`、`Hua.Todo.Host/Hua.Todo.Host.csproj`、`docs/manual/08-构建与开发指南.md`
|
||
- 可与 v1.3.0 工单 03、05 并行
|
||
|
||
## 四、验收标准(Given-When-Then)
|
||
|
||
| # | 场景 | GIVEN | WHEN | THEN |
|
||
|---|---|---|---|---|
|
||
| 1 | 根路径返回前端 HTML(模式 B) | Host 已 `dotnet build`,且 `wwwroot/index.html` 有内容 | HTTP GET `http://localhost:5173/` | 返回 200;`Content-Type: text/html`;body 含 `<div id="app">`(来自 Hua.Todo.Web 模板/index.html) |
|
||
| 2 | SPA 路由 fallback | 同 1 | HTTP GET `http://localhost:5173/settings`(前端内部路由) | 返回 200;body 是 `index.html` 全文,**不是** 404 页 |
|
||
| 3 | API 路由不被 fallback 覆盖 | 同 1 | HTTP POST `/api/cloud-sync/probe` | DynamicApi 正常处理(200 / 503 都行,但不是 index.html) |
|
||
| 4 | MSBuild Target:`dotnet publish Hua.Todo.Host` | 干净克隆(删 node_modules 和 dist),Node 已装 | 执行 `dotnet publish src/Hua.Todo.Host -c Release -o ./publish-host` | `publish-host/wwwroot/` 下有 `index.html`、`assets/` 等 Hua.Todo.Web build 产物;且 publish-host 启动后 `GET /` 满足验收 1 |
|
||
| 5 | MSBuild Target 增量构建(不重复 npm run build) | Hua.Todo.Web src 文件未变动,已执行过一次 build | 再次执行 `dotnet build src/Hua.Todo.Host` | npm build 阶段跳过后直接 copy(Inputs/Outputs 正确);日志出现 "Skipping target BuildHuaTodoWeb"(或等价跳过提示) |
|
||
| 6 | 开发联调(文档可执行) | 新环境 clone 后 Node 已装、.NET 10 SDK 已装 | 按 docs/manual 新增章节的步骤执行(两条命令:1. Vite dev;2. Host run) | Vite :5174 页面打开、API 请求能到 Host :5173;云同步探测能返回 `isReachable` JSON(与 307 修复后的链路一致) |
|
||
|
||
## 五、并行冲突规避
|
||
|
||
| Touch List | 共享文件策略 | 编译绿线策略 |
|
||
|---|---|---|
|
||
| `Hua.Todo.Host/Program.cs` | 只在 `app.UseDynamicApi();` **之前**插入 `UseDefaultFiles/UseStaticFiles`;在 `app.Run()` **之前**追加 `MapFallbackToFile("index.html")`(若已存在 `/api/cloud-sync/proxy-settings` endpoint 则不改动) | `dotnet build Hua.Todo.Host.csproj` 0 错误 |
|
||
| `Hua.Todo.Host/Hua.Todo.Host.csproj` | 追加 `<Target Name="BuildHuaTodoWebWebRoot" BeforeTargets="BeforeBuild" ...>` 节点;**不修改任何现有 PropertyGroup/ItemGroup/Target** | 同编译 + `dotnet publish` 产出验证 |
|
||
| `docs/manual/08-构建与开发指南.md` | 末尾追加两个新小节标题,不改原有章节顺序 | 纯 Markdown |
|
||
| `test/Hua.Todo.Host.Tests/...` | 新建 `WebRootStaticFileTests.cs`(独立文件),不修改既有测试类 | `dotnet test Hua.Todo.Host.Tests` 新增 + 既有全部通过 |
|
||
|
||
## 六、风险与回滚
|
||
|
||
| 风险 | 影响 | 应对策略 |
|
||
|---|---|---|
|
||
| `npm install` 时长慢(首次)+ 网络差导致构建失败 | CI publish 超时 | MSBuild Target 加 `ContinueOnError="WarnAndContinue"` + 清晰错误日志:"Hua.Todo.Web build skipped,deploy wwwroot 是空的——请手动构建 Hua.Todo.Web 后重试" |
|
||
| `MapFallbackToFile` 顺序放错,覆盖掉 `/api/*` 或 `/swagger/*` | API / Swagger 404 | 在 Program.cs 写明确顺序:`UseSwagger → UseStaticFiles → UseAuthentication/Authorization → UseDynamicApi → MapMcpServer → MapFallbackToFile`;并在集成测试里同时验证 fallback 和 API 都正常 |
|
||
| 增量构建 Inputs/Outputs 写粗了导致漏 build(或反复 build) | 前端代码变更后不生效 / 构建变慢 | Inputs 精确到 `Hua.Todo.Web/package.json` + `Hua.Todo.Web/src/**/*.{ts,vue,css,html}`;Outputs 精确到 `wwwroot/index.html` |
|
||
| CI 环境 Node 不存在 | 构建报错 | Target 检测不到 `node`/`npm` 时仅 Warning,不阻塞 Host API 层 build(生产环境可由外部 CI 先 build 前端再打包) |
|
||
|
||
## 七、与其他工单的语音/UI 入口衔接
|
||
|
||
> 按 [05-多入口功能同步规范.md](../../../.trae/rules/项目/05-多入口功能同步规范.md) 第 3.2 条:纯基础设施调整无需检查双入口。
|
||
|
||
| 入口 | 已规划 | 方案 |
|
||
|---|---|---|
|
||
| UI | ✅(本次就是 UI 托管入口补齐) | 模式 B `http://localhost:5173/` 直接返回 Hua.Todo.Web |
|
||
| 语音 | ❌(无需) | 不涉及业务操作 |
|
||
|
||
---
|
||
|
||
**创建日期**:2026-08-08
|
||
**关联规则**:[01-项目架构.md §3 模式 B](../../../.trae/rules/项目/01-项目架构.md)
|
||
**关联工单**:v1.3.0 工单 05;v1.2.0 工单 06.1(Admin 管理后台前端)
|