Document run preview npm stall fix
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
# 运行预览前端安装卡顿修复设计
|
||||
|
||||
## 背景
|
||||
|
||||
运行预览会为生成的前台和后台前端分别执行:
|
||||
|
||||
```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 或新的依赖安装调度服务。
|
||||
Reference in New Issue
Block a user