构建自己的 VS Code 插件

4,835 阅读4分钟

一、前言

VS Code 是前端开发现在最流行的 IDE 之一。

那么大家在用 VS Code 的时候有没有安装自己喜欢的一些插件呢?

在享受各种插件带来的丝滑体验的同时,有没有考虑过自己动手写一个插件呢?

下面我们就手搓一个。

温馨提示:写这篇文章是因为最近在社区看到了不少好玩的插件,然后为了满足好奇心对插件的实现做了简单的了解。在这里做一个分享,个人水平有限,如有错误之处还请观众老爷们指点一下。

二、概览

2.1 本文章描述

读完这篇文章,你可以学到什么?

  • 如何构建,运行,调试,测试插件
  • 如何利用 VS Code 丰富的插件 API
  • 学习代码示例以帮助您入门

2.2 插件可以做哪些事情?

以下是扩展API可以实现的一些示例:

三、初始化

3.1 创建

输入以下指令,安装 YeomanVS Code Extension Generator

npm install -g yo generator-code

然后运行生成器会支持用户进行一些自定义配置。如下图:

配置包括:

  • 要创建什么类型的扩展?TypeScript / JavaScript

  • 你的插件叫什么名字?

  • 你的插件的标识符是什么?

  • 关于你的插件有什么描述?

  • 要初始化 git 存储库?

  • 要使用哪个包管理器?npm / yarn

我这边就按照官方示例做个示范:

3.2 调试

那么项目创建完成之后,如何开始调试插件呢?

在终端输入指令 code ./helloworld 会在编辑器中打开这个文件夹。

在编辑器中按 F5,将会新开一个编辑器窗口用于调试开发中的插件。

在新窗口命令面板 (Ctrl + Shift + P) 中输入 Hello World 运行命令,你将看到 Hello World from HelloWorld! 的通知。

四、生命周期

从生命周期上来看,分为三个部分:

  • Activation Event:设置插件激活的时机。位于 package.json 中。
  • Contribution Point:设置在 VS Code 中哪些地方添加新功能,也就是这个插件增强了哪些功能。位于 package.json 中。
  • Register:在 extension.js 中给要写的功能用 vscode.commands.register...Activation EventContribution Point 中配置的事件绑定方法或者设置监听器。位于入口文件(默认是 extension.js)的 activate() 函数中。

package.json

package 中和插件相关的主要包括以下几个属性,其中 main 是插件的入口文件相对路径。

// package.json
{
  "activationEvents": [
    "onCommand:vscode-demo.helloWorld"
  ],
  "main": "./extension.js",
  "contributes": {
    "commands": [
      {
        "command": "vscode-demo.helloWorld",
        "title": "Hello World"
      }
    ]
  }
}

4.1 Activation Event

初始的 Hello World 只在执行 vscode-demo.helloWorld 的命令后激活插件。当我们给 package.json 中 activationEvents 属性添加 onCommand:vscode-demo.helloVscode 之后,我们就可以在 vscode-demo.helloVscode 命令下激活插件,做其他的事情了。

// package.json
{
  "activationEvents": [
    "onCommand:vscode-demo.helloWorld",
    "onCommand:vscode-demo.helloVscode"
  ]
}

4.2 Contribution Point

Contribution 说明了插件对哪些项目进行了增强。

例如我们要新加一个 vscode-demo.helloVscode 指令:

// package.json
{
  "contributes": {
    "commands": [
      {
        "command": "vscode-demo.helloWorld",
        "title": "Hello World"
      },
      {
        "command": "vscode-demo.helloVscode",
        "title": "Hello VS Code"
      }
    ]
  }
}

4.3 Register

完整的 API 是:registerCommand(command: string, callback: (args: any[]) => any, thisArg?: any): Disposable

这个的主要功能是给功能代码(callback)注册一个命令(command),然后通过 subscriptions.push() 给插件订阅对应的 command 事件。

例如我们完善下类似 Hello World 的功能。

// extension.js
function activate(context) {
  let disposable = vscode.commands.registerCommand(
    "vscode-demo.helloWorld",
    () => {
      vscode.window.showInformationMessage("Hello World!");
    }
  );

  context.subscriptions.push(disposable);

  // 新增的订阅事件
  let helloVscode = vscode.commands.registerCommand(
    "vscode-demo.helloVscode",
    () => {
      vscode.window.showInformationMessage("Hello VS Code!");
    }
  );
  context.subscriptions.push(helloVscode);
}

五、Webview

Webview API 允许扩展在 VS Code 中创建完全可自定义的视图。例如,内置的 Markdown 扩展使用 Web 视图来呈现 Markdown 预览。除了 VS Code 的本机 API 所支持的之外,Webview 还可以用于构建复杂的用户界面。

可以将网络视图视为 iframe 扩展控制的 VS Code 内部。Web 视图可以在此框架中呈现几乎所有 HTML 内容,并且它使用消息传递与扩展进行通信。这种自由性使 webview 变得异常强大,并开辟了一系列新的扩展可能性。

接下来,我们尝试把下面这个日常表情用 Webview 显示出来。

先在 package.json 中加入新的指令

// package.json
{
  "activationEvents": [
    ...
    "onCommand:vscode-demo.openNewTab"
  ],
  "main": "./extension.js",
  "contributes": {
    "commands": [
      ...
      {
        "command": "vscode-demo.openNewTab",
        "title": "Start new Webview",
        "category": "Open New Tab"
      }
    ]
  },
}

然后我们调整下 extension.js

// extension.js
const vscode = require("vscode");

function activate(context) {
  ...

  context.subscriptions.push(
    vscode.commands.registerCommand("vscode-demo.openNewTab", () => {
      // Create and show a new webview
      const panel = vscode.window.createWebviewPanel(
        "startCoding", // Identifies the type of the webview. Used internally
        "开机上班,开始混底薪", // Title of the panel displayed to the user
        vscode.ViewColumn.One, // Editor column to show the new webview panel in.
        {} // Webview options. More on these later.
      );

      panel.webview.html = getWebviewContent();
    })
  );
}
exports.activate = activate;

function deactivate() {}

function getWebviewContent() {
  return `<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>开机上班,开始混底薪</title>
</head>
<body>
    <img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/07af40dfd51946f1b0c7aa60ae4e6dca~tplv-k3u1fbpfcp-watermark.image" width="300" />
</body>
</html>`;
}

module.exports = {
  activate,
  deactivate,
};

好,我们重新编译下试试。

如下图:

混底薪的 gif 就显示出来了,感兴趣的同学都可以玩一下。

具体还有很多高级的功能待大家慢慢去发掘。

六、感谢

  • 如果本文对你有帮助,就点个赞支持下吧!感谢阅读。