# 研发工单 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 含 ``/`<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 管理后台前端)