现状
我们开发的VSCode插件目前只支持司内的业务,暂时无法上架VSCode的官方市场。随着不断的迭代,每发一个新版本,需要通知到所有用户,用户还要手动下载和安装最新的版本,这样的更新效率非常低。那么上架到商店的插件可以自动更新,私有插件如何更新呢?针对私有插件源和私有插件的管理,官方并没有给到相应的解决办法,对应的github issue一直悬而未决。只能自己想办法,通过一些调研,最终可以利用vscode的安装api去实现私有插件的自动更新。
方案
1. 上传visx文件到COS存储
以版本号命名文件夹,上传打包产物vsix到COS存储,这样就提供vsix的存储地址。
2. 管理插件的最新版本号
数据库中存储插件的最新版本号,提供可访问的接口。
3. 检测版本
插件active时,通过上一步的接口获取插件的最新版本号,与本地已安装插件的版本号进行对比。
import { get } from 'lodash';
import * as vscode from 'vscode';
import semver from 'semver';
// 获取本地安装的插件版本号
const data = await fetchLastVersion();
// 获取本地安装的插件版本号
const extension = vscode.extensions.getExtension(EXTENSION_ID);
const currentVersion = get(extension, 'packageJSON.version');
// 比较
const needUpdate = semver.gt(data.version ?? '0.0.1', currentVersion);
4. 更新插件
根据上一步的结果,如需更新,下载最新的vsix,起一个新进程利用code --install-extension进行覆盖安装。需要注意的是,用户的code不一定在系统的path中,我们需要获取vscode的appRoot,从而获取code程序。
const name = getPackageName(data.version);
const file = await download(data.version, name);
if (file) {
const result = await install(file);
if (result) {
vscode.window.showInformationMessage('Auto update success, please restart VSCode');
}
}
// 下载
async function download(version: string, name: string): Promise<string|false> {
return new Promise(resolve => {
// 创建文件夹
if (!fs.existsSync(downloadDir)) {
fs.mkdirSync(downloadDir);
}
const url = DOWNLOAD_ADDRESS + version + '/' + name;
https.get(url, (res) => {
const filePath = path.join(downloadDir, name);
const file = fs.createWriteStream(filePath);
res.pipe(file);
file.on('finish', () => {
file.close();
resolve(filePath);
});
}).on('error', (err) => {
resolve(false);
});
});
}
// 安装
async function install(fileAddress: string): Promise<boolean> {
return new Promise((resolve) => {
let cmd = '';
if (os.platform() === 'win32') {
cmd = path.join(vscode.env.appRoot, '../../bin', 'code.cmd');
} else {
cmd = path.join(vscode.env.appRoot, 'bin', 'code');
}
child_process.execFile(cmd, ['--install-extension', fileAddress], {
}, (error, stdout, stderr) => {
if (!error) {
resolve(true);
// 安装成功后,删除文件
fs.unlinkSync(fileAddress);
} else {
resolve(false);
}
});
});
}
用户重新打开VSCode时,新版本插件生效。最终了实现私有插件的自动更新。