npm依赖的一些问题与resolution的使用
之前对resolution认知几乎为零, 遇到了问题才理解了.
再结合之前幽灵依赖的事聊一下npm依赖的问题.
线上bug, 本地没问题
有个项目使用到了code-mirror
作为文本编辑器, 在一个新版本发生了”按回车不能换行”的问题.
在生产环境的控制台看不到任何报错, 而在本地功能却没有问题.
遇到本地生产不一致, 就要思考本地与生产的流程有什么不同, 再逐个验证.
我把本地node_modules删除重新安装后, 可以重现生产问题了.
这就是典型的第三方库不讲武德, npm install默认会给兼容小版本的^
修饰, 而第三方库在小版本中加入了会使之前代码行为不一致的特性.
以前有个厉害的同事经常指导我锁版本, 现在算是理解了.
那就锁版本, 但本地白屏了
我把所有code-mirror
相关的依赖都锁了版本, 并重新安装, 按我的想象, 所有依赖应该会到以前正常运行的状态.
仔细看了报错, 是code-mirror
加载插件报了”非法插件”, 因为用instance of
判断了是否插件类的实例, 而code-mirror
的库互相依赖, 导致加载了不同版本的”插件类”, 导致instance of
判否, 再导致白屏.
我认为需要具体描述一下这个过程:
我的项目有2个依赖: A: 1.0.0, B: 1.0.0.
这2个依赖都锁定了版本为”1.0.0”.
但 B 也把 A 作为了依赖, 并且在package.json
中的声明是向后兼容小版本: ^1.0.0.
在npm安装过程中, B的依赖向后兼容, 就安装了 A@1.5.0 的版本.
而我的项目安装了A@1.0.0 的版本, 是我在我的项目中锁定的, 而我并不能修改 B 项目中的package.json
.
最后, B 的代码中, 引入了 A@1.5.0 的Plugin
类, 并且实例化.
而在我项目的执行过程中, 判断了 B 代码中的 1.5.0的实例 是否是 A@1.0.0的实例, 他们来自2个文件, 在混淆后甚至变成了不同字母, 那是不可能通过instance of
判定了, 所以报错.
问了朋友, 告诉我在自己package.json
中添加一个resolution
字段, 声明{ A: 1.0.0 }
, 这样项目中的A
依赖都会安装1.0.0
的版本.
其实前公司一直用resolution
固定react
版本, 因为react如果存在不同的版本, 也会白屏, 而我一直没去稍微深入了解下.
幽灵依赖导致的白屏
然后再重新说一下之前遇到的严重的依赖问题.
同事的一个组件升级了, 我升级了组件版本, 没有本地运行就推代码, 导致测试环境页面白屏了.
公司项目用的monorepo, 比如react
, react-redux
这样的每个项目都要用的依赖, 在子项目中就不声明了.
同事组件的新版本声明了react-redux
的版本, 是比外层声明低的版本.
在代码中有使用forwardRef
, 这个api 是react-redux
7 以后才有的.
之前使用了外层的react-redux
没有问题, 当自己模块就存在react-redux
老版本后, 就使用老版本作为resolve, 于是就报错了.
node的resolve机制是很简单的, 先找自己目录的node_modules, 再递归往父级找, 找到找不到为止.
总结
如果只遇到上述三个问题中的一个, 我们很容易就会得出结论: 比如”要锁版本”, 或者”要写resolution”, 或者”要杜绝幽灵依赖, 自己import的内容一定要声明”.
但结合一起看会发现, 在一些事情上”准确”, “合理” 是需要具体情况去把握的.
比如我盲目杜绝幽灵依赖, 可能导致项目依赖了某个库的多个版本, 导致打包时间与打包体积的大幅上升.
要记着依赖版本相关的一些特性, 清楚自己在做什么, 具体情况具体处理.
首先得记得, 只修改依赖的版本号, 也是可能影响其他代码的, 记得先运行再提交代码 :(
然后总结下上述问题发生的原因, 都很简单, 遇到问题放松分析就可以:
- 线上本地不同的问题可能是线上npm没缓存导致, 可以本地删除node_modules重新安装来重现.
- 在锁版本的时候也要同时使用resolution来锁定深层依赖版本.
- 在利用幽灵依赖的时候有包的安装和升级要检查新依赖. (在npm install后会在命令行提示的)
(本文完)
如果你可以 点击这个链接打赏我5毛,对我的鼓励比500块还多很多
本文遵循 cc协议
你可以在注明出处和非商用的前提下任意复制及演绎