safety-eval-website/docs/dependency-issues-guide.md

253 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 依赖问题排查指南
本文档记录本项目在依赖安装与启动过程中的实际问题、根因与解决方案。
## 项目环境基线
| 项 | 值 |
| --- | --- |
| 包管理器 | **pnpm 11.17.0**(唯一,仓库只有 `pnpm-lock.yaml`,无 `package-lock.json` |
| Node | v22.23.1 |
| 构建工具 | Rspack 1.7.12(经 `@cqsjjb/scripts` 驱动) |
| 开发端口 | **8080**(定义在 `jjb.config.js` |
| 启动命令 | `npm run serve:development` |
| pnpm 配置文件 | **`pnpm-workspace.yaml`**(项目已无 `.npmrc` |
> **最重要的一条**:本项目使用 pnpm 11。**pnpm 11 不再从 `.npmrc` 读取 `public-hoist-pattern`、`hoist`、`node-linker` 等安装配置**,这些配置已迁移到 `pnpm-workspace.yaml`,并改用小驼峰命名(`publicHoistPattern`、`nodeLinker`)。项目原有的 `.npmrc` 因此完全失效,已被删除。
---
## 1. `Unable to resolve loader babel-loader` — loader 未被提升
这是本项目实际遇到的**唯一阻塞启动**的错误。
### 现象
```text
ERROR in × Unable to resolve loader babel-loader??ruleSet[1].rules[2].use[0]
1 ERROR in child compilations
Rspack 1.7.12 compiled with 2 errors
```
### 根因
`babel-loader``@cqsjjb/scripts` 的**传递依赖**,并未写在本项目 `package.json` 中。pnpm 默认采用隔离式isolated`node_modules` 布局,传递依赖只存在于 `node_modules/.pnpm/` 虚拟存储中不会出现在顶层。Rspack 解析 loader 时按名称在顶层查找,因而失败。
项目原本试图用 `.npmrc``public-hoist-pattern[]=*loader` 解决但如上所述pnpm 11 已不读取该文件。可用以下命令验证配置是否真正生效:
```powershell
pnpm config get public-hoist-pattern # 失效时返回 undefined
```
### 解决方案
`pnpm-workspace.yaml` 中声明 `publicHoistPattern`
```yaml
publicHoistPattern:
- '*loader*'
- '*webpack-plugin*'
- 'react-refresh'
- '@babel/*'
- 'postcss'
- 'autoprefixer'
```
注意通配符要写成 `*loader*` 而非 `*loader`,确保能匹配 `babel-loader`、`css-loader` 等带连字符的包名。
修改后必须重新安装才能生效(见下方「配置变更后如何让安装生效」)。
### 验证
```powershell
@('babel-loader','style-loader','css-loader','less-loader','react-refresh','html-webpack-plugin') |
ForEach-Object { "$_ : " + (Test-Path "node_modules/$_") }
```
全部为 `True` 即成功。正常情况下 `node_modules` 顶层目录数约为 44 个(未提升时为 32 个)。
---
## 2. `ERR_PNPM_IGNORED_BUILDS` — build scripts 被忽略
### 现象
```text
[ERR_PNPM_IGNORED_BUILDS] Ignored build scripts: @parcel/watcher, core-js, es5-ext,
x-data-spreadsheet, zy-react-library
Run "pnpm approve-builds" to pick which dependencies should be allowed to run scripts.
```
### 根因
pnpm v10+ 出于安全考虑,默认禁止依赖执行 `postinstall` 等 build scripts需显式放行。
项目 `pnpm-workspace.yaml` 中原先写的是 `allowBuilds`,且值为占位文本 `set this to true or false`,属于无效配置。
### 解决方案
改用 `onlyBuiltDependencies` 数组格式,并删除无效的 `allowBuilds` 块:
```yaml
onlyBuiltDependencies:
- '@parcel/watcher'
- core-js
- es5-ext
- x-data-spreadsheet
- zy-react-library
```
若安装后警告仍然出现,显式执行一次重建即可:
```powershell
pnpm rebuild @parcel/watcher core-js es5-ext x-data-spreadsheet zy-react-library
```
> 该报错会让 `pnpm install` 以退出码 1 结束,但依赖本身已装完,属于**非阻塞**问题,不影响启动。
---
## 3. 配置变更后如何让安装生效
### 现象一:改了配置但没有任何效果
`pnpm install` 在 lockfile 未变化时会跳过重新链接,`publicHoistPattern` 之类的布局配置不会被应用。
**解决**
```powershell
pnpm install --force
```
### 现象二:安装中断,提示需要清空 `node_modules`
```text
The modules directory at "node_modules" will be removed and reinstalled from scratch.
Proceed? (Y/n)
```
改变 hoist 配置会要求重建整个 `node_modules`,而在无 TTY 的自动化环境中该确认无法响应,安装会挂起或中断。
**解决**:以 CI 模式跳过交互确认。
```powershell
$env:CI='true'; pnpm install
```
---
## 4. DVA namespace 缺失
### 现象
控制台错误:
```text
[ERROR] 注册数据层失败,原因:无法匹配路径'xxx'
```
### 根因
`@cqsjjb/jjb-dva-runtime` 会扫描 `src/api/` 下的子目录,并用目录名去匹配 `src/enumerate/namespace/index.js``defineNamespace("xxx")` 声明的字符串,匹配不上则报错。
新增了 `src/api/<name>/` 却没有同步添加 namespace 定义时就会触发。
### 解决方案
`src/enumerate/namespace/index.js` 中补充:
```js
export const NS_XXX = defineNamespace("xxx");
```
### 本项目当前状态
`src/api/` 下共 6 个目录,而 namespace 只定义了 4 个:
| 目录 | namespace | 说明 |
| --- | --- | --- |
| `global` | `NS_GLOBAL` | 已定义 |
| `bi` | `NS_BI` | 已定义 |
| `driver` | `NS_DRIVER` | 已定义 |
| `register` | `NS_REGISTER` | 已定义 |
| `institution` | — | **未定义** |
| `supervision` | — | **未定义** |
`institution``supervision` 导出的是普通 fetch 函数,并非 DVA model 结构,当前启动日志中**未出现**注册报错,因此不影响运行。是否补充 namespace 属于业务设计决策:若后续要把它们改造成 DVA model则必须同步添加定义。
> **约定**:新增 `src/api/<name>/index.js` 并按 DVA model 结构编写时,务必在 `src/enumerate/namespace/index.js` 中添加 `defineNamespace("<name>")`。
---
## 5. 端口占用 `EADDRINUSE`
### 现象
```text
Error: listen EADDRINUSE: address already in use 0.0.0.0:8080
```
本项目端口为 **8080**(见 `jjb.config.js`),通常是上次的开发服务器进程未正常退出。
### 解决方案
```powershell
# 查看占用情况
netstat -ano | findstr :8080
# 只杀真正处于 LISTEN 状态的进程
Get-NetTCPConnection -LocalPort 8080 -State Listen -ErrorAction SilentlyContinue |
ForEach-Object { Stop-Process -Id $_.OwningProcess -Force }
```
> `netstat` 输出中的 `TIME_WAIT` / `FIN_WAIT` 是待回收的残留连接,**不占用**端口,无需处理。只有 `LISTENING` 才是真正的占用。
---
## 标准启动流程
```powershell
# 1. 安装依赖(首次或配置变更后)
$env:CI='true'; pnpm install
# 2. 若提示 build scripts 被忽略
pnpm rebuild @parcel/watcher core-js es5-ext x-data-spreadsheet zy-react-library
# 3. 启动开发服务器
npm run serve:development
```
成功标志:
```text
Rspack 1.7.12 compiled successfully in 22.97 s
```
服务地址 <http://localhost:8080/>。首次编译约 20-30 秒,日志停在 `wait until bundle finished: /` 属正常现象,需耐心等待打包完成。
---
## 检查清单
- [ ] 确认使用 **pnpm**,不要混用 npm 安装(会破坏 `node_modules` 结构)
- [ ] pnpm 安装类配置一律写在 `pnpm-workspace.yaml`**不要**写进 `.npmrc`
- [ ]`pnpm config get <key>` 验证配置是否真正生效,别假设它已加载
- [ ] 改动 hoist 类配置后使用 `pnpm install --force`,并设 `$env:CI='true'` 跳过交互确认
- [ ] 遇到 `Unable to resolve loader` 时,检查该 loader 是否已提升到 `node_modules` 顶层
- [ ] 新增 DVA model 目录时同步添加 namespace 定义
- [ ] 端口冲突只需关注 `LISTENING` 状态的进程
---
## 附:已废弃的排查思路
以下做法在早期版本文档中出现过,**当前项目不适用**,请勿采纳:
| 废弃做法 | 说明 |
| --- | --- |
| 手动添加 `history@^4.10.1` 作为直接依赖 | `@cqsjjb/jjb-common-lib` 自身已声明 `history@^5.3.0`pnpm 会正确链接到 `.pnpm` store。强行加 v4 会造成版本冲突。 |
| 把 `resolutions` 迁移为 `pnpm.overrides` | 当前 `package.json` 已无 `resolutions` 字段,无需处理。 |
| 改用 `npm install --legacy-peer-deps` | 项目已无 `package-lock.json`,统一使用 pnpm。npm 的扁平化布局会与 pnpm 结构冲突。 |
| 在 `.npmrc` 中设置 `shamefully-hoist` / `hoist` / `node-linker` | pnpm 11 不再从 `.npmrc` 读取这些配置,`.npmrc` 已从项目中删除。 |
| 处理 `react-router` 相关依赖问题 | 项目未依赖 `react-router``src` 中亦无引用。 |