背景
有一个2016年开始研发的Vue项目,最近在做部署的时候出了问题。进入部分模块后,功能无法使用,而且控制台报错:
1 | [Vue warn]: Failed to mount component: template or render function not defined. |
其中Scroller标签是采用了vue-scroller组件,经过观察,凡是使用了这个组件的模块,都有相同的问题。
问题排查
使用Vue的配置?
根据错误提示搜索,能找到的原因是Vue的使用模式不当,前端无法编译template。但着和项目的问题不符合,因为其他模块并没有出现问题,而且同样也有使用第三方模块的情况。所以这种情况可以排除。
package.json?
那么只可能是vue-scroller出了问题。查看了一下package.json的修改记录,没有相关的依赖版本修改记录,一直是这个配置:
"vue-scroller": "^2.1.2"
vue-scroller更新?
查看了一个vue-scroller的github项目,发现最近几个月有修改的记录,新版本已经是2.2.4了,再查看项目中使用的版本,是2.2.4。看来是版本导致的问题。
经过比较两个版本发现,模块导出部分做了很关键的修改:
1 | @@ -1,10 +1,18 @@ |
可以看到,导出的不再是Scroller,而是包含Scroller的另外一个对象,这就是导致问题的原因。
解决
类似vue-scroller这样项目更新不受我们控制,我们能控制的是受不受这种更新的影响。
显然可以选择使用最新版本的第三方模块,但要把引用部分全部修改,即便这样还有稳定性、潜在问题的风险在其中,这不是一个好的方案。
这里只需要限定项目使用早先的版本,项目代码不需要修改,只需要修改package.json中的"vue-scroller": "^2.1.2"
为"vue-scroller": "2.1.2"
。
回顾——捷径
查询npm项目信息
本例中就可以使用:npm info vue-scroller
,版本更新情况一目了然。
查询当前项目使用第三方npm包的版本
本例子中就可以使用:npm list vue-scroller
。不必再去模块目录查看包文件。
回顾——npm依赖包版本号控制
npm的版本号遵循语义化软件版本规范。
考虑使用这样的版本号格式:XYZ (主版本号.次版本号.修订号)修复问题但不影响API 时,递增修订号;API 保持向下兼容的新增及修改时,递增次版本号;进行不向下兼容的修改时,递增主版本号。
这里只辨析相关定义规则。
^2.1.2
表示什么?
^2.1.2
等价于>=2.1.2 <3.0.0
,所以按照先前的配置文件,会义无反顾的采用2.2.4版本。
容易混淆的~2.1.2
表示什么?
~2.1.2
等价于>=2.1.2 <2.(1+1).0
,等价于>=2.1.2 <2.2.0
。
这里有一篇详细的介绍。
vue-scroller项目为什么要做修改
我们来看早先版本(2.1.2):
1 | import Scroller from './components/Scroller.vue' |
新版本(2.2.4):
1 | import Scroller from './components/Scroller.vue' |
作者也说明了修改的目的:“export as a Vue Plugin”,再对比源代码,可见修改的目的是为了使得vue-scroller成为vue的一个插件。
反思
对于项目依赖的第三方包,如何声明依赖版本号?
声明为固定版本号至少不会出错,其他情况就要看第三方包作者对语义化版本号规范的执行的情况了。本例中,声明的依赖版本号没有错误:API保持向下兼容的版本都可以采用。
作为第三方包的作者,升级的时候如何更新版本号?
在本例中,作者的2.2.4版本导出部分做了不兼容的修改,原来直接导出的Scroller不在新版本导出了,发布更新的时候应该更新主版本号。如果我们自己发布npm项目也要注意这点,毕竟遵守规范是合作的前提。