253 lines
8.3 KiB
Markdown
253 lines
8.3 KiB
Markdown
# 依赖问题排查指南
|
||
|
||
本文档记录本项目在依赖安装与启动过程中的实际问题、根因与解决方案。
|
||
|
||
## 项目环境基线
|
||
|
||
| 项 | 值 |
|
||
| --- | --- |
|
||
| 包管理器 | **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` 中亦无引用。 |
|