VSCode私有插件自动更新策略

1,399 阅读2分钟

现状

我们开发的VSCode插件目前只支持司内的业务,暂时无法上架VSCode的官方市场。随着不断的迭代,每发一个新版本,需要通知到所有用户,用户还要手动下载和安装最新的版本,这样的更新效率非常低。那么上架到商店的插件可以自动更新,私有插件如何更新呢?针对私有插件源和私有插件的管理,官方并没有给到相应的解决办法,对应的github issue一直悬而未决。只能自己想办法,通过一些调研,最终可以利用vscode的安装api去实现私有插件的自动更新。

方案

auto-update-private-plugin.png

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时,新版本插件生效。最终了实现私有插件的自动更新。