解决pnpm中的 Pinia 版本冲突:Cannot read properties of undefined (reading ‘_s‘)
1. 问题现象
在 Vue3 + Pinia + PNPM + Vite 工程中,应用本身依赖 pinia
,同时内部私有组件库(web-sdk
)也依赖 pinia
。
运行时浏览器控制台抛出:
Uncaught TypeError: Cannot read properties of undefined (reading '_s')
at useStore (pinia.mjs:42:15)
2. 根因分析
PNPM 会把 同一个包 + 相同版本 + 相同 peer 依赖解析结果 合并到同一目录。
只要 三方包中的peer 依赖(typescript / vue)版本不一致,即使主版本号相同,也会被判定为 “不同解析结果”,用pinia2.0.36版本为例,因为pinia 2.0.36中依赖了vue和typescript和@vue/composition-api,其中typescript和composition-api是可选的
"peerDependencies": {"@vue/composition-api": "^1.4.0","typescript": ">=4.4.4","vue": "^2.6.14 || ^3.2.0"
},
"peerDependenciesMeta": {"typescript": {"optional": true},"@vue/composition-api": {"optional": true}},
所以应用和组件库中的vue版本不同的话,就会生成两份物理副本,造成最终dist文件中存在2份pinia文件:
node_modules/.pnpm/
├─ pinia@2.0.36_vue@3.4.21_typescript@5.3.3/
└─ pinia@2.0.36_vue@3.5.13_typescript@5.8.2/
3. 解决方案
方案 | 思路 | 适用场景 | 实施成本 |
---|---|---|---|
方案 1 | 允许存在两份物理副本,但运行时强制指向同一模块 | 无法统一 peer 依赖版本(如组件库已发布) | ⭐ |
方案 2 | 彻底统一 peer 依赖版本,让 PNPM 只保留一份 | 能同时修改应用 + 组件库 | ⭐⭐ |
3.1 方案 1:Vite dedupe 强制对齐
在 vite.config.ts 中声明:
import { defineConfig } from 'vite'export default defineConfig({resolve: {dedupe: ['pinia'], // 关键一行},
})
原理:
Vite 在解析 import ‘pinia’ 时,永远使用第一次遇到的副本,从而保证全局符号唯一。
无需改动任何 package.json,最快落地。
3.2 方案 2:统一 peer 依赖版本
盘点组件库 web-sdk 的 peerDependencies,在应用侧对齐版本
重新安装依赖:
rm -rf node_modules pnpm-lock.yaml
pnpm install
4 小结
关键词 | 一句话总结 |
---|---|
重复实例 | PNPM 因 peer 依赖版本不同生成多份 pinia,导致全局 _s 未定义 |
快速修复 | vite.resolve.dedupe: ['pinia'] 运行时强制对齐 |
根治手段 | 统一应用与组件库的 vue + typescript 版本,让 PNPM 只保留一份 |