vscode-cats插件是如何开发的?小包带你来实现一下

1,902 阅读7分钟

「这是我参与11月更文挑战的第17天,活动详情查看:2021最后一次更文挑战

前言

经过两个周的努力,昨天成功发布人生第一个插件 vscode-cats ,本文给大家介绍一下插件的开发过程,顺便也给自己做个记录。

插件下载: VSCode 扩展中直接搜索 vscode-cats 即可

如果能给 github 点个 star 就更完美了。

最开始开发 vscode-cats 时,感觉真的是暗无天日、遥遥无期。首先文档全是英文,看起来还是有几分吃力;二就是这种插件的模式实现 VSCode 并不提倡,因此 VSCode 官方并未提供类似的案例,但皇天不负有心人,多种方式去搜索、查询,终于查到了 background 插件(我感觉 background 插件的开发大佬很有可能是当前模式的先导者),后面又查到了 vscode-live2d 插件,通过钻研两位大佬的设计思路,终于最后成功做出 vscode-cats 插件。

环境准备

在开发 VSCode 插件之前,我们需要先安装两个依赖

  • yeoman: npm install -g yo
  • generator-code: npm install -g generator-code

初始化项目

进入要开发插件的目录,执行 yo code 指令,就会进入如下界面:

yocode.png

vscode-cats 插件使用的是 ts 开发,因此我们选择 New Extension (TypeScript) ,根据界面中要求操作,等到依赖安装完毕,插件 demo 项目初始化完毕。

初始化后的目录结构大致如下(只显示重要部分):

├── CHANGELOG.md        // 版本更迭记录
├── README.md           // 插件说明文档
├── src
│   └── extension.ts    // 入口文件
├── package.json        // 
├── tsconfig.json       // ts配置
├── test                // 测试

核心文件介绍

学习 VSCode 插件开发,有两个特别重要的文件: package.json extension.ts ,学会这两个文件后,就能进行简单的 VSCode 插件开发。

package.json

package.json 声明插件和命令的配置文件,用来注册命令等配置。

package.json 有很多字段属性可以配置,这里我就简介几个比较重要的配置。

activationEvents 属性

扩展的活动事件数组,在那些情况下事件会被激活。

demo 中配置的时 onCommand 指令,通过命令可以触发

"activationEvents": [
    "onCommand:demo.helloWorld"
],

插件中使用的是 "*" ,所有类型的事件都可以触发激活

"activationEvents": [
    "*"
],

关于 activationEvents 更详细的配置: code.visualstudio.com/api/referen…

contributes 配置贡献点

常用的有 commandconfiguration 等。

command

与活动事件列表里的 onCommand 指令相对应,在这里配置完毕后,就可以通过命令进行访问。

demo 中配置如下:

"commands": [
    {
        "command": "demo.helloWorld",
        "title": "Hello World"
    }
]

configuration

configuration 配置的属性会在 setting.json 中和 VSCode 插件设置页面通过 UI 格式显示。

撸猫插件给喵咪添加了下面的配置:

配置描述
vscode-cats.enabledtrue:启用插件、false:禁用插件
vscode-cats.model更换喵咪
vscode-cats.modelWidth自定义喵咪宽度
vscode-cats.modelHeight自定义喵咪高度
vscode-cats.moveX自定义喵咪水平位置
vscode-cats.moveY自定义喵咪垂直位置
vscode-cats.opacity设置喵咪透明度
vscode-cats.position设置喵咪左右定位

下面以两个属性举一下例子:

"configuration": [
    {
    "title": "喵咪配置",
    "type": "Object",
    "properties": {
        "vscode-cats.enabled": {
        "type": "boolean",
        "default": true,
        "description": "是否启用喵咪"
        },
        "vscode-cats.model": {
            "type": "string",
            "enum": [
                "tororo",
                "hijiki"
            ],
            "default": "tororo",
            "description": "选那只喵咪"
            }
        },
    }
]

配置完毕后,就可以在 setting.jsonUI 中看到属性

configSetting.png

configUi.png

extension.ts

extension 文件为项目的入口文件,该文件中提供两个重要方法: active deactive

  • active: 插件激活时执行的函数
  • deactive: 插件被销毁时调用的函数
export function activate(context: vscode.ExtensionContext) {
	// 这里的代码只会在插件激活时执行一次
	console.log('Congratulations, your extension "demo" is now active!');
	// 定义在 package.json 中的命令在这里定义
	// 提供 registerCommand 来注册实现代码
        // commandId 参数必须与 package.json 匹配
	let disposable = vscode.commands.registerCommand('demo.helloWorld', () => {
        // 当命令触发时,这里的代码执行
        // 显示提示信息框
		vscode.window.showInformationMessage('Hello World from demo!');
	});
	context.subscriptions.push(disposable);
}
// 插件停用时调用
export function deactivate() {}

vscode-cats 开发

上面简单介绍了 VSCode 插件开发中必须要了解的基本知识,有了这些知识做基础,接下来一起看一下 vscode-cats 的实现。

架构

首先来看一下 vscode-cats 插件的项目结构

vscode-catConstr.png

  • extension.ts: 项目入口
  • FileType.ts: 文件类型(未修改过、hack过的旧版本、hack过的新版本)
  • getHTML.ts: 获取能渲染喵咪的 workbench.html
  • HTML.ts: 实现检查、替换、恢复 workbench.html
  • originHTML: 删除插件,恢复 workbench.html 文件
  • Home.ts: 项目的根文件
  • uninstall.ts: 插件卸载
  • utils: 工具函数
  • version.ts: 插件版本
  • vsHelp.ts: 封装 VSCode 自身的信息提示功能

实现思路

  1. 预备工作
    • 通过 fs 模块获取到 workbench.html 路径
    • 编写读取文件内容 getContent、更改文件内容 saveContent 方法
    • 封装信息提示框函数 showInfo 和提示信息并重启 showInfoRestart 函数
    • 通过 vscode.workspace.getConfiguration 获取到插件的配置项
    • 将能实现喵咪的 HTML 代码添加到 getHTML.ts 并且将配置项集成到 HTML
    • 将原来的 workbench.htmlHTML 代码保存到 origin HTML.ts
  2. 安装插件或激活插件:
    • 编写 install 方法: 获取到 config 信息,将 config 信息传递给 getHTML ,将生成的 HTML 代码写入 workbench.html
    • 判断插件是否为第一次安装、旧版本,如果是,执行 install 方法
  3. 卸载插件或关闭插件:
    • uninstall: 从 originHTML 获取到原来的 HTML 代码,写入 workbench.html

如何获取当前版本是否为新版本: 通过给 workbench.html 添加标识实现,例如当前插件添加的标识是 <!-- /*ext.${extName}.ver.${version}*/ -->

核心代码

  1. 获取 workbench.html 路径
const base = path.dirname(require.main.filename);
const filePath = path.join(
    base,
    "vs",
    "code",
    "electron-browser",
    "workbench",
    "workbench.html"
);
  1. 读写文件
export const saveContent = function (filePath, content: string): void {
  fs.writeFileSync(filePath, content, "utf-8");
};
export const getContent = function (filePath): string {
  return fs.readFileSync(filePath, "utf-8");
};
  1. 读取插件配置
let config = vscode.workspace.getConfiguration(this.configName); 
  1. install
public install(refresh?: boolean): void {
    let lastConfig = this.config; // 之前的配置
    let config = vscode.workspace.getConfiguration(this.configName); // 当前用户配置
    // 1.如果配置文件改变到时候,当前插件配置没有改变,则返回
    if (!refresh && JSON.stringify(lastConfig) === JSON.stringify(config)) {
      return;
    }
    // 之后操作有两种:1.初次加载  2.配置文件改变
    // 2.两次配置均为,未启动插件
    if (!lastConfig.enabled && !config.enabled) {
      return;
    }
    // 3.保存当前配置
    this.config = config; // 更新配置
    // 4.如果关闭插件
    if (!config.enabled) {
      this.uninstall();
      vsHelp.showInfoRestart(this.extName + "已关闭插件,请重新启动!");
      return;
    }
    // 5.hack 样式
    // 自定义的样式内容
    let content = getNewHtml(config, this.extName, this.version).replace(
      /\s*$/,
      ""
    );
    // 将插件的HTML写入 workbench.html 文件
    saveContent(this.filePath, content);
    vsHelp.showInfoRestart(this.extName + " 已更新配置,请重新启动!");
  }
  1. uninstall
private uninstall(): boolean {
    try {
        let content = renewHTML();
        saveContent(this.filePath, content);
        return true;
    } catch (ex) {
        return false;
    }
}

打包

打包的实现比较简单,安装 vsce 依赖包(npm install -g vsce)。

之后通过 vsce package 就可以将插件打包成 vsix 文件。

最后就可以把 vsix 安装到 VSCode 中试一下是否可用。

vsix.png

发布

关于发布我就不多啰啰了,具体可以参考官方文档。

传送门: Publishing Extensions

但一定注意在 maketPlace 注册开发者时,需要翻墙,那个注册页面访问了谷歌。(血泪教训)

往期精彩文章

后语

伙伴们,如果大家感觉本文对你有一些帮助,给阿包点一个赞👍或者关注➕都是对我最大的支持。

另外如果本文章有问题,或者对文章其中一部分不理解,都可以评论区回复我,我们来一起讨论,共同学习,一起进步!

如果感觉评论区说不明白,也可以添加我的微信(li444186976)或者 qq(3315161861) 详细交流,名字都是战场小包。