Files
yidaima/RuoYi-Vue/docs/superpowers/specs/2026-06-18-run-preview-npm-install-stall-design.md
2026-06-18 12:14:43 +08:00

97 lines
4.2 KiB
Markdown
Raw 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.

# 运行预览前端安装卡顿修复设计
## 背景
运行预览会为生成的前台和后台前端分别执行:
```text
npm install && npm run dev
```
生成项目使用 Vue CLI 4因此安装时出现 `svgo@1.3.2` 等 deprecated 警告属于旧依赖提示,不是启动失败。
现场检查确认:
- 两个前端没有 `package-lock.json`,每次都需要重新解析完整依赖树。
- 每个前端、每次预览都使用独立的空 npm 缓存。
- 重新启动预览时只终止 Java 持有的外层 shell安装阶段尚未监听端口现有按端口清理无法找到仍在运行的 npm/node 子进程。
- 多次启动后遗留的 npm 进程并行下载和解压依赖持续争抢网络、CPU 和磁盘,日志又长时间停留在 deprecated 警告附近,因此表现为“卡住”。
## 目标
1. 停止或重新启动预览时,终止该预览启动的整棵后端和前端进程树。
2. 前台、后台前端以及后续预览复用同一份 npm 下载缓存。
3. 保留当前 Vue 2 / Vue CLI 4 生成模板,不在本次修复中升级依赖栈。
4. 保留端口清理作为服务已经监听后的兜底措施。
## 方案
### 受管进程
`RunPreviewProcessRunner` 在 Windows 上通过无用户配置的 PowerShell 包装器启动命令。包装器在执行实际命令前记录自身 PID并等待子命令退出。
Java 侧返回一个委托标准 `Process` 行为的受管进程对象,同时保留 PID 记录位置。这样不依赖 Java 9 的 `ProcessHandle`,可继续运行在当前 Java 8 环境。
在非 Windows 平台上继续使用现有 shell 启动方式;进程终止逻辑保持标准 `Process.destroy()` / `destroyForcibly()` 行为。
### 进程树终止
`RunPreviewProcessKiller` 停止受管 Windows 进程时:
1. 读取包装器记录的根 PID。
2. 执行 `taskkill /PID <pid> /T /F`,终止根进程及全部后代。
3. 等待 Java 持有的进程退出。
4. 如果 PID 不可用或系统命令失败,回退到当前的 `destroy()` / `destroyForcibly()`
5. 最后继续按端口查找并清理已经进入监听状态的残留进程。
PID 文件位于对应预览工作区内,名称唯一;进程退出或停止后尽力删除。
### 共享 npm 缓存
把当前每个工作区下的:
```text
.easycode-preview/npm-cache/frontend
.easycode-preview/npm-cache/admin-frontend
```
改为预览根目录下的共享缓存:
```text
preview-workspaces/.npm-cache
```
前台、后台前端和后续预览都设置同一个 `NPM_CONFIG_CACHE`。npm 自身的内容寻址缓存支持并发访问;保留 `audit=false``fund=false` 和更新检查关闭配置,并启用 `prefer-offline`,优先复用已经下载的包,缺失内容仍可联网获取。
共享缓存只保存 npm 下载内容,不复用生成项目的 `node_modules`,避免不同项目依赖树互相污染。
## 错误处理
- PID 文件尚未生成、内容无效或 `taskkill` 不可用时,不让停止接口失败,回退到标准 Java 进程终止。
- npm 缓存目录无法创建时,启动预览失败并返回明确错误。
- deprecated 警告继续展示,避免隐藏真实安装输出;它们不改变预览状态。
## 测试
### 自动化测试
- 先新增失败测试,证明 Windows 受管进程能够暴露进程树根 PID且终止器会针对该 PID 请求整树终止。
- 验证 PID 缺失时仍会回退并结束 Java `Process`
- 更新运行预览服务测试,验证前台与后台前端获得同一个、位于预览根目录的 npm 缓存。
- 验证 npm 环境启用 `prefer-offline`,同时保持允许联网下载。
- 运行 `RunPreviewProcessRunnerTest`、进程终止器测试和 `FrontProjectRunPreviewServiceImplTest`
### 手工验证
1. 启动同时包含前台和后台前端的运行预览。
2. 在安装期间停止并重新启动预览,确认旧 npm/node 子进程消失。
3. 首次安装完成后再次启动,确认共享缓存被复用,安装阶段明显缩短。
4. 确认两个前端端口均可访问,停止后端口被释放。
## 非目标
- 升级 Vue、Vue CLI、webpack 或 deprecated 间接依赖。
- 生成或维护 `package-lock.json`
- 跨项目复用 `node_modules`
- 引入 Docker 或新的依赖安装调度服务。