前言
前几天有个人跟我反馈说,她fork了我右键菜单那个开源项目,一直无法打包成功。我寻思着应该不可能吧,当我尝试打包时,果然翻车了??。
经过了一番调试后,终于找到了问题所在,本文就跟大家分享下这个问题从发现到解决的整个过程,欢迎各位感兴趣的开发者阅读本文。
排查问题
因为我电脑重装过几次系统,一些放在github上的项目我就没有备份,我把项目(https://github.com/likaia/vue-right-click-menu-next/)重新clone到本地,安装依赖项后运行了build命令,意想不到的事情发生了:它报错了??
- ERROR Failed to compile with 4 errors 11:02:26 AM
- error in ./src/components/right-menu.vue
- Module parse failed: Unexpected token (1:0)
- File was processed with these loaders:
- * ./node_modules/eslint-loader/index.js
- You may need an additional loader to handle the result of these loaders.
上述报错的意思是找不到处理vue文件的相关loader,我就纳闷了,这不可能啊,几个月前插件写好时还能打包的,现在咋就突然不能打包了呢。
可能是node版本的问题
难道是我node版本的问题?插件写好到现在代码一直没动过,唯一变化的就是我升级了node版本,降级node版本太麻烦,于是我安装了node版本管理工具n。
因为我的系统是macos,我可以直接用brew来安装它,命令如下:
- brew install n
如果你是windows系统,你可以通过npm包的形式来安装它,命令如下:
- npm install -g n
安装完成后,我去找了下我写这个项目时所发布的node版本v14.14.0,我们用n工具来安装并切换它:
- n 14.14.0
我们运行node --version命令看下是否成功。
一切准备就绪,我寻思着应该不会出现问题了吧??,结果运行后,我傻眼了,仍然报着同样的错误??
node版本管理工具有挺多的,除了文中说的n还有nvm、npx,感兴趣的开发者可自行了解。
发现猫腻(yarn.lock)
当我一筹莫展发呆时,突然发现目录树中的yarn.lock变色了,看来是有改动了,我寻思着不可能啊,我没动package.json中的依赖项啊,怎么会发生变化呢?
重新创建个项目试试
既然lock文件发生了变化,那我重新创建个项目试试,把相关依赖项拷过去再打包看看。
我们继续使用Vue CLI作为插件搭建环境,对此不熟悉的开发者请移步我的另一篇文章:使用CLI开发一个Vue3的npm库
- vue create test-vue3-project
项目创建完成后,我把相关文件拷贝了过去,修改了package.json中的build命令。
- {
- "build": "vue-cli-service build --target lib --name vueRightMenuPlugin src/main.ts"
- }
运行命令后,它居然打包成功了??
找到问题
经过前面的一番折腾,创建了一个新的项目他就好了,那我比对下这俩项目有啥不同之处,那么问题就迎刃而解了。
经过比对后,我发现了package.json中的不同之处:
- "dependencies": {
- "core-js": "^3.6.5",
- "vue": "^3.0.0"
- }
- "peerDependencies": {
- "core-js": "^3.6.5",
- "vue": "^3.0.0"
- }
区别就在于,vue和core-js这两个包的位置,问题应该就出在这里了。
我们来验证下吧,将dependencies中的那两个包放到peerDependencies中,重新install下,再build看下。
不出意料,果然报错了。
那么为啥我的项目之前能跑,现在却没法跑了,我想应该是因为之前改了后,我没有重新install的缘故吧??。
解决问题
那么,既然找到问题了,我们反过来,把右键菜单的peerDependencies下的两个包放到dependencies下,再看看问题能否得到解决。
当我满怀信心的执行build命令后,结局却让我很失望。
是的,他换了个错误??
image-20210912132222990
看报错是类型无法自动推导,这就很怪异了。那么就只能尝试下我的三板斧了:
- 重启软件
- 重启电脑
- 删除项目,重新clone,重新install依赖
前两个尝试过后,发现并无卵用,只好用了最后一个方法。
重新install后,执行了build命令,成功解决了这个问题。
为什么呢
问题是解决了,那么为什么要那样做呢?接下来就带大家深入研究下dependencies和peerDependencies。
dependencies
dependencies是package.json中的一个属性,里面放运行代码时所需的依赖,在install时这些包会被安装,打包项目时,这里面的包也会被打包进去。
peerDependencies
peerDependencies也是package.json中的一个属性,这个单词翻译过来是对等依赖的意思,这里面的包在install时并不会安装,打包项目时,这里面的包也不会被打包进去。
两者存在的问题
如果将依赖包放在dependencies下,那么当别人在他的项目中引入你的插件时,会出现下述情况:
- 他项目里没有引入你所需的依赖包,那么你插件所依赖的包会被安装
- 他项目里引入了你所需的依赖包:
- 版本号一致,那么你所需的依赖包不会被安装,插件将共用项目里的依赖包
- 版本号不一致,那么你所需的依赖包就会被安装,项目里就存在了两套不同版本的依赖
版本号一致那还好,万事大吉。版本号不一致时,你插件所依赖的那个包需要的功能与调用者项目里安装的那个版本的包并无区别,那么调用者的项目将变得臃肿起来,又多安装了一份依赖。
如果将依赖包放在peerDependencies下,对插件开发者是不友好的,会出现下述问题:
- install的时候,所需的依赖不会安装,使用ide开发时会报错找不到相关依赖。
- build的时候,因为依赖未安装,导致无法打包(文章开头提到的报错)
这么看的话,peerDependencies这个属性,好像没啥用了。当然存在即合理,如果大家有什么更好的看法,欢迎在评论区留言讨论。
解决方案
知道他们各自的优点和缺点后,我也就知道了如何解决这个问题。
既然dependencies中的依赖包只要和调用者的版本号一致,就不需要重新安装依赖,那我们把它的版本号放开,给个范围,这样不就可以了??
在package.json中的版本号可以带下述符号:
- ~波浪号,匹配最新补丁版本号,即版本号的第三个数字,例如~3.0.0就会匹配3.0.x版本,将在3.1.0停止
- ^插入符号,匹配次要的版本号,即版本号的第二个数字,例如^3.0.0就会匹配任何3.x.x版本,将在4.0.0停止
- >、<、>=、<=比较运算符,匹配的就是这个区间的版本,例如>3.0.0 <= 3.1.4,就会匹配这个区间的版本号
如果不带符号,那么它就是精确匹配。
本文中,用的是^3.0.0,满足了我们插件的使用场景,因此不需要更改。