幽灵依赖
简单讲,就是包的依赖不需要指定版本。比如你封装了一个工具包ABC,该包的package.json在开发期间依赖了React/moment/dayjs等第三方库,但实际发布到仓库时可以从devDependencies、dependencies字段中移除掉这些依赖,但实际项目import "ABC"使用时并不会报错,被包ABC被丢掉的这些依赖叫幽灵依赖。
npm
npm支持幽灵依赖,只要你的项目package.json中有声明并安装这些依赖包即可,开发工具包不需要指定任何依赖。node的包寻址方式从引用文件所在目录开始,往上不断找node_modules文件夹,由于npm使用扁平化的方式管理包,所以一定能寻址到node_modules文件夹。
pnpm
pnpm幽灵依赖支持方式比较绕。pnpm一般用于多项目整合(monorepo),用例代码会单独拆成一个子项目,使用pnpm开发工具包项目必须指定包的版本,否则用例项目引用工具包项目会出现Can't resolve XXX报错。原因在于pnpm使用软连接重定向了node的包寻址,直接重定向到工具包项目的源代码目录,如果你的工具包项目node_modules中使用幽灵依赖方案,就会直接抛异常,因为各个子项目的目录结构是平行的,往上寻址就会到达根目录。
解决
使用pnpm开发,如果工具包子项目必须指定依赖版本,但用例项目又指定依赖版本,就会造成依赖的实现差异,这是填了旧坑结果又引出新坑?实际上pnpm把所有包都放到了根项目node_modules/.pnpm目录中,只要你在根项目(项目最外层文件夹)install幽灵依赖,就会命中依赖。如果工具包被发布到仓库,从线上install,那么会被安装到根项目node_modules/.pnpm目录中,幽灵依赖也会命中。