# 内网实现vscode插件自动更新

# 背景

vscode插件在外网中会自动查询插件市场并更新,但是在内网中,由于连不到插件市场,每次更新都要手动安装插件包,这就容易降低升级意愿。

# 检查版本更新

之前的做法是,在流水线中自动打包生成vsix插件包

然后每次打开vscode插件的时候,拉取FEX-AIGC代码仓库的tag,与本地package.json进行版本比较,如果有更新,则调用vscode.window.showInformationMessage进行弹窗提示,并附属下载vsix最新包的链接。

缺点就是每次都要手动下载后安装,十分影响使用体验。

# 自动更新

处理方式也很简单

同样判断需要更新时,直接从之前的更新地址将vsix插件包下载下来

下载完成后通过node子进程执行vscode的安装插件命令即可

核心命令就是执行vscode安装目录里的code脚本

xx/bin/code --install-extension path

在安装成功后弹窗提示用户重启vscode

具体代码:

function exec(...args: Parameters<typeof spawn>) {
  const [command, spanwArgs = [], options = {}] = args
  const { timeout, ...restOpts } = options
  return new Promise((resolve, reject) => {
    // 需要手动timeout: https://github.com/nodejs/node/issues/43704
    const childProcess = spawn(command, spanwArgs, restOpts)
      .on('close', resolve)
      .on('error', reject)
    if (timeout) {
      setTimeout(() => {
        childProcess.emit('close')
        reject(new Error('ETIMEDOUT'))
      }, timeout)
    }
  })
}

async function autoUpdate(latestVersion: string) {
  const url = `xxx.vsix`
  const savePath = path.resolve(process.cwd(), `fex/vsix/${latestVersion}.vsix`)
  const folderPath = path.dirname(savePath)
  // 确保文件夹存在
  fs.mkdirSync(folderPath, { recursive: true })
  const stream = fs.createWriteStream(savePath)
  stream.on('finish', async () => {
    await exec(`${process.cwd()}${path.sep}bin${path.sep}code`, ['--install-extension', savePath], { stdio: 'ignore', timeout: 3000 })
    const buttonLabel = await vscode.window.showInformationMessage(
      `插件${name}自动更新完毕, 是否重启该窗口`,
      '是',
      '否',
    )
    if (buttonLabel === '是')
      vscode.commands.executeCommand('workbench.action.reloadWindow')
  })
  http.get(url, (res) => {
    res.pipe(stream)
  })
}

# 总结

通过自动更新,使用者无需再手动安装,也提升了使用FEX-AIGC插件的意愿