# vue outdated
'(experimental) check for outdated vue cli service / plugins'
上面是代码中的功能描述原文,我理解这个是说:实验性的功能,用来检查 服务(@vue/cli-service) 或者 插件(官方插件@vue/cli-plugin-* 自定义插件vue-cli-plugin-*) 是否过期
# 调试配置
{
"program": "${workspaceFolder}/packages/@vue/cli/bin/vue",
"args": [
"outdated"
]
}
上面的这个调试配置是能够正常执行的,但是有一点缺憾的是,我现在还没有发现如何能能够在某个项目中执行 vue outdated
命令,然后能够在当前的 vue-cli 项目中打断点的方式。
所以其中的某些代码逻辑就不能实际执行到,当然这个对我们查看代码会有影响,但是没那么大。
# 源码探索
# 命令注册
program
.command('outdated')
.description('(experimental) check for outdated vue cli service / plugins')
.option('--next', 'Also check for alpha / beta / rc versions when upgrading')
.action((cmd) => {
require('../lib/outdated')(cleanArgs(cmd))
})
# 主要逻辑
@vue/cli/lib/outdated.js
这个文件中也很清晰,加载 ./Upgrader
类,实例化,调用 checkForUpdates
方法。
const Upgrader = require('./Upgrader')
async function outdated (options, context = process.cwd()) {
const upgrader = new Upgrader(context)
return upgrader.checkForUpdates(options.next)
}
首先 Upgrader
实例化时,构造函数中初始了两个属性,并且又实例化了 PackageManager 类。
this.pkg = getPkg(this.context)
this.pm = new PackageManager({ context })
这个 PackageManager 类我们可以通过他的方法来大致了解他的作用
class PackageManager {
async runCommand (command, args) {...}
async install () {
...
return await this.runCommand('install')
}
async add () {
...
return await this.runCommand('add', [packageName, ...args])
}
async remove (packageName) {
return await this.runCommand('remove', [packageName])
}
async upgrade (packageName) {
...
return await this.runCommand('add', [packageName])
}
}
主要是针对依赖包的处理,安装、添加、移除、升级,版本比较等。
下面看下这个方法,因为要做版本比较,所以需要有比较的源 -- 也就是最新版本。getRemoteVersion
这个方法是用来获取远程版本的
async getRemoteVersion (packageName, versionRange = 'latest') {
const metadata = await this.getMetadata(packageName)
if (Object.keys(metadata['dist-tags']).includes(versionRange)) {
// 这里判断如果版本匹配,则和就直接返回版本号
return metadata['dist-tags'][versionRange]
}
const versions = Array.isArray(metadata.versions) ? metadata.versions : Object.keys(metadata.versions)
// 然后这里返回所有匹配的版本中,最大的版本。
return semver.maxSatisfying(versions, versionRange)
}
其中的 this.getMetadata(packageName)
这个方法的内容可以看下,
const url = `${registry.replace(/\/$/g, '')}/${packageName}`
try {
// 请求url,url类似这样 http://npm.intra.xiaojukeji.com/@vue/cli
metadata = (await request.get(url, { headers })).body
metadataCache.set(metadataKey, metadata)
return metadata
} catch (e) {
error(`Failed to get response from ${url}`)
throw e
}
我通过curl的方式模仿request请求,curl http://npm.intra.xiaojukeji.com/@vue/cli
拿到的返回结果如下
"_id" : "@vue/cli",
"_rev" : "45453609",
"name" : "@vue/cli",
"description" : "Command line interface for rapid Vue.js development",
"dist-tags" : {
"next" : "4.1.0",
"latest" : "4.2.3"
},
"versions" : {
"4.1.1" : {
"name" : "@vue/cli",
"description" : "Command line interface for rapid Vue.js development",
"version" : "4.1.1",
"author" : {
"name" : "Evan You"
},
},
"4.1.2": {},
...
}
接下来再看 checkForUpdates
方法,首先是获取当前项目依赖中的 if (name !== '@vue/cli-service' && !isPlugin(name))
主要是找服务和插件,其中 isPlugin 这个方法尤其值得好好品一下:
const pluginRE = /^(@vue\/|vue-|@[\w-]+(\.)?[\w-]+\/vue-)cli-plugin-/
exports.isPlugin = id => pluginRE.test(id)
看到这个正则我只能空叹:“厉害!”,当然我们大致可以理解是匹配了名字来判断是否为插件。
获取到需要过期的插件后,通过控制台输出,从而提示用户进行升级。