# 12 — pnpm dev 热更新 Status: resolved Type: task ## 需求 > pnpm dev 开发模式支持热更新 ## 做法 监听 `src/` 与 `wallpapers/`,按改动**只跑必要的那几步**构建,然后经 SSE 通知浏览器。 | 改动 | 跑什么 | 浏览器怎么更新 | 实测 | | --- | --- | --- | --- | | `src/styles/*.css` | 重铺产物 | **只换样式表** | 850 ms | | `src/runtime/*` | tsc runtime + 重铺产物 | 整页刷新 | 1.1 s | | `src/simulator/*` | tsc simulator(产物里也带模拟器时再重铺) | 整页刷新 | 600 ms | | `wallpapers/**`、模板、vendor、`VERSION` | 重铺产物 | 整页刷新 | 850 ms | | 构建失败 | — | **只报错,不刷新** | — | 全量 `pnpm build` 是 2.2 秒;按改动拆开之后,改样式只要 0.85 秒,改模拟器 0.6 秒。 ### 为什么 CSS 单独一条路 整页刷新要重新下载 3.4 MB 骨架、重建 Spine 播放器、面板状态全丢。改样式时这些全是白费—— 换一下 `` 的 `href`(加个 `?t=` 时间戳)就够了。实测确认:换完样式表, `window` 上的标记**还在**,也就是页面确实没有重载。 ### 为什么构建失败不刷新 刷新会把一个半成品页面端上来,而错误信息在控制台里——很容易被当成"改了没生效"。 现在构建失败只在左下角显示一条红药丸,页面保持原样。 ### 为什么状态药丸挂在 `` 下 与模拟器面板同一个理由:`body` 上会被打 `transform`/`filter`(翻转、颜色选项), 挂 `body` 里会跟着壁纸一起被镜像、被调色。 ## 两个必须记住的约束 1. **绝不能监听 `dist/`**。构建写 `dist/`,监听它就是一个死循环。只监听 `src/`、`wallpapers/`、`VERSION`。 2. **`--with-sim` 产物里也有一份模拟器**,而且它的驱动排在调试服注入的那份**之前**(幂等闸先到先得)。 所以那种构建下,改模拟器必须连产物一起重铺,否则浏览器会一直跑旧模拟器。 调试服启动时会探一次产物里有没有模拟器,据此决定要不要多跑那一步。 ## 调试期代码不许进产物 热更新客户端连的是 `/__dev/events`——那在真实 WE 里、在任何静态托管上都不存在。 它由 `tools/dev.ts` 的 `html()` 注入,`tools/build.ts` 的 `renderIndexHtml` 完全不碰它。 这条**钉进了 `check:dist`**,不再靠人工抽查。实测过它会拦: ``` ✗ collection-all/index.html 里有调试服专属的 /__dev/events ``` (一个从不失败的检查等于没有检查——所以注入标记确认它会红,再还原。) 三种产物都确认过干净:默认产物 0 处、`--with-sim` 产物 0 处、自包含包 0 处。 ## 验证 `tools/checks/verify-hot-reload.mts`:真的改源文件,用"页面上的标记还在不在"区分两种更新方式 (只看"页面变了没有"是分不出"整页刷新"和"只换样式表"的): - 页面注入了热更新客户端;`/__dev/events` 返回 `text/event-stream` - 改 CSS → 被改的那条样式表 href 换成带 `?t=` 的新地址、**标记还在**(没整页重载)、换上的确实是新内容 - 改 runtime → **标记被抹掉**(整页刷新)、刷新后面板重新挂上 - 测完还原源文件,并确认仓库里没有探针注释残留 其余回归全绿:`pnpm check`、调试服与浏览器冒烟、面板还原度、四档自包含包 `file://`、 静态托管预览、6 组渲染与重构前逐像素相同。