最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 如何开发一款vscode插件

    正文概述 掘金(清沫)   2021-07-04   582

    如何开发一款vscode插件

    vscode 在近几年颇受开发人员喜爱,这得益于它的轻量性和非常的插件市场。你可以在插件市场找到大量功能强大的插件帮助提高编码效率。但是(总有那么个但是?)在实际的开发中,还是会有一些特殊的定制需求找不到特别合适的插件,此时我们就可以撸起袖子,自己造一个轮子。

    插件功能

    vscode 赋予了插件 非常多的能力,让它们几乎可以在方方面面对 vscode 进行武装升级,插件的主要能力包括:

    • 提供新主题(包括编辑器配色,文件图标等等)
    • 支持新编程语言的语法(提供高亮,代码补全,错误检查等等功能)
    • 提供程序调试功能
    • 自定义命令,快捷键,菜单
    • 自定义工作区 Webview

    开发怎样的插件?

    在笔者写单元测试时,常常会遇到以下问题:

    1. 需要在源文件和对应的单测文件来回切换,而 vscode 并不具有 webstorm 那样的源文件测试文件快速切换的功能。使得整个切换体验不佳
    2. 为源文件创建单测文件时,如果文原则是将源文件文件夹和测试文件文件夹分开时,往往需要递归创建测试文件。比如src/module/child/a.ts,需要层层创建tests/module/child/a.test.ts文件,这尤为麻烦?

    基于这些痛点,笔者开发一款 vscode 插件,用于在源文件测试文件之间快速切换,以及快速创建单测文件。插件效果:

    如何开发一款vscode插件

    插件功能:

    • 查找源文件对应的测试文件。如果只找到一个可能的文件,则直接切换;如果找到多个,则显示下拉选择框供用户选择
    • 快速创建单测文件。支持两种模式,将单测文件和源文件放在一起,或者将所有单测文件单独放在特定文件夹中,并按源文件目录结构组织
    • 提供丰富的配置能力,用户可自定义单测文件后缀规范

    你可以点击 此链接,或者在 vscode 插件市场搜索** Find Test File **体验:

    如何开发一款vscode插件

    环境准备

    • nodejs,建议稳定版
    • git

    首先安装 yeoman 脚手架工具,以及 vscode 官方提供的脚手架工具:

    npm install -g yo generator-code
    

    接下来执行以下命令交互式创建插件项目:

    yo code
    

    如何开发一款vscode插件

    项目结构

    现在,插件项目已经创建完成,项目目录结构如下:

    .
    ├── node_modules
    ├── CHANGELOG.md
    ├── README.md
    ├── package.json
    ├── src
    │   ├── extension.ts
    │   └── test
    │       ├── runTest.ts
    │       └── suite
    │           ├── extension.test.ts
    │           └── index.ts
    ├── tsconfig.json
    ├── vsc-extension-quickstart.md
    ├──.vscode
    	  ├── extensions.json
    		├── launch.json
    		├── settings.json
    		└── tasks.json
    └── yarn.lock
    

    其中:

    • .vscode文件夹存放程序运行和调试相关命令
    • vsc-extension-quickstart.md文档介绍了插件的入门知识和运行方式,是项目创建后需要首先关注的点
    • src文件夹中存放插件源代码,需要重点关注这一块(src/test存放插件 e2e 测试代码,暂时不用关注)
    • package.json除了包含常规 node 项目配置属性外,还包含插件配置属性,也需要重点关注

    默认情况下,项目已经配置好运行调试参数,按下F5即可运行插件(其实就是运行.vscode/launch.json中的Run Extension命令):

    如何开发一款vscode插件

    我们先从package.json入手,插件配置相关代码片段如下:

    {
      "name": "test",
    	"displayName": "test",
    	"engines": {
    		"vscode": "^1.57.0"
    	},
    	"categories": [
    		"Other"
    	],
    	"activationEvents": [
            "onCommand:test.helloWorld"
    	],
    	"main": "./out/extension.js",
    	"contributes": {
    		"commands": [
    			{
    				"command": "test.helloWorld",
    				"title": "Hello World"
    			}
    		]
    	}
    }
    
    • namedisplayName不必多提,是插件的名字和显示名字(即在插件市场的名字)
    • enginesvscode版本是指该插件所兼容的 vscode 版本
    • categories表示插件的分类,但是它和keywords有所不同,只能从选择 官方指定的列表 中选择
    • main表示插件程序入口
    • activationEvents表示何时 激活插件
    • contributes表示如何 定制插件功能

    再来看看src/extension.ts中的内容:

    import * as vscode from "vscode";
    
    export function activate(context: vscode.ExtensionContext) {
      console.log('Congratulations, your extension "test" is now active!');
      // 自定义命令
      let disposable = vscode.commands.registerCommand("test.helloWorld", () => {
        // 触发弹出框
        vscode.window.showInformationMessage("Hello World from test!");
      });
    	// 将命令注册到执行上下文中
      context.subscriptions.push(disposable);
    }
    
    export function deactivate() {}
    

    extension.ts暴露两个方法:

    1. active:在插件激活时运行,通常在其中注册自定义命令
    2. deactive:在插件禁用时运行

    这两部分就是开发插件的核心,我们将整个流程拉通一下:

    如何开发一款vscode插件

    撸起袖子开始干

    插件配置

    首先在package.json中声明插件的命令,以及插件激活的条件:

    {
     
      "activationEvents": [
        "onCommand:find-test-file.jumpToTest",
        "onCommand:find-test-file.createTestFile"
      ],
      "contributes": {
        "commands": [
          {
            "command": "find-test-file.jumpToTest",
            "title": "Jump To Source/Test File",
            "category": "Find Test File",
            "icon": "$(preferences-open-settings)",
            "enablement": "resourceExtname =~ /.[jt]sx?/"
          },
          {
            "command": "find-test-file.createTestFile",
            "title": "Create Test File For Current",
            "category": "Find Test File",
            "icon": "$(file-add)",
            "enablement": "resourceExtname =~ /.[jt]sx?/"
          }
        ]
      }
    }
    

    commands配置项中,添加jumpToTestcreateTestFile两个命令,除了常规commandtitle配置外,还多出了几项配置(更多commands配置请查阅 官方文档):

    • category:用于在命令面板中将命令分组

    如何开发一款vscode插件

    • icon:命令所对应图标(后续menus配置才会用到),格式为$(name),vscode 自带 一套图标
    • enablement:表明何时在命令面板中显示命令,上述配置表明只有在当前打开的文件是tstsx),jsjsx)时,才能在命令面板中显示

    activationEvents保持是在执行对应命令时再激活插件(更多激活条件请查阅 官方文档)。图省事的话,也可以直接设置为*,即在 vscode 启动后就激活,毕竟能用就行,是吧。

    如何开发一款vscode插件

    当然,保持在必要时候才激活插件是一个更好的实践。

    通过命令面板选择命令执行总是不够方便,快捷键才是王道。可以通过keybindings属性增加快捷键配置(更多keybindings配置请查阅 官方文档):

    {
      "contributes": {
        "keybindings": [
          {
            "command": "find-test-file.jumpToTest",
            "key": "ctrl+shift+t",
            "mac": "cmd+shift+t",
            "when": "resourceExtname =~ /.[jt]sx?/"
          },
          {
            "command": "find-test-file.createTestFile",
            "key": "ctrl+alt+t",
            "mac": "cmd+alt+t",
            "when": "resourceExtname =~ /.[jt]sx?/"
          }
        ]
      }
    }
    
    • Mac 和 Window 的快捷键有所不同,Mac 中的cmd键等同于 Window 的ctrl,需要分别配置
    • when表示快捷键什么时候启用,和commandenablement配置类似

    既然有了快捷键,能不能有鼠标右键之类的快捷方式呢?能!通过menus属性增加配置(更多menus配置请查阅 官方文档):

    {
      "contributes": {
        "menus": {
          "editor/context": [
            {
              "command": "find-test-file.jumpToTest",
              "group": "1_find-test-file",
              "when": "resourceExtname =~ /.[jt]sx?/"
            },
            {
              "command": "find-test-file.createTestFile",
              "group": "1_find-test-file",
              "when": "resourceExtname =~ /.[jt]sx?/"
            }
          ],
          "editor/title": [
            {
              "command": "find-test-file.jumpToTest",
              "group": "navigation",
              "when": "resourceExtname =~ /.[jt]sx?/"
            },
            {
              "command": "find-test-file.createTestFile",
              "group": "navigation",
              "when": "resourceExtname =~ /.[jt]sx?/"
            }
          ]
        }
      }
    }
    

    如何开发一款vscode插件 如何开发一款vscode插件

    插件还需要提供用户配置的能力。比如:不同项目对测试文件的后缀命名是不同的,有些是a.test.ts,有些是a.spect.ts。这部分能力由configuration配置提供:

    {
      "contributes": {
        "configuration": {
          "title": "Find Test File",
          "properties": {
            "findTestFile.basic.testSuffix": {
              "type": "string",
              "default": "\\.(spec|test)",
              "markdownDescription": "xxxxxx"
            },
            "findTestFile.basic.excludeFolder": {
              "type": "array",
              "default": [
                "node_modules"
              ],
              "items": {
                "type": "string"
              },
              "uniqueItems": true,
              "markdownDescription": "xxxxxx"
            },
            "findTestFile.createIfNotFind.enable": {
              "type": "boolean",
              "default": false,
              "markdownDescription": "xxxxxx"
            },
            "findTestFile.createIfNotFind.preferStructureMode": {
              "type": "string",
              "default": "separate",
              "enum": [
                "separate",
                "unite"
              ],
              "markdownEnumDescriptions": [
                "xxxxxx",
                "xxxxxx"
              ],
              "markdownDescription": "xxxxxx"
            },
            "findTestFile.createIfNotFind.preferTestDirectory": {
              "type": "object",
              "default": {
                "separate": "__tests__",
                "unite": "__tests__"
              },
              "properties": {
                "separate": {
                  "type": "string"
                },
                "unite": {
                  "type": "string"
                }
              },
              "required": [
                "separate",
                "unite"
              ],
              "additionalProperties": false,
              "markdownDescription": "xxxxxx"
            }
          }
        }
      }
    }
    

    在设置页面的显示结果如下:

    如何开发一款vscode插件

    配置项可以是数组,字符串,布尔值,枚举,对象,具体配置参见 官方文档。

    插件代码

    src/extension.ts主要功能:

    • 注册插件两个命令
    • 判断 vscode 当前打开的文件以及当前工作目录,只有在打开了特定的文件时,才需要执行业务逻辑
    import vscode from "vscode";
    
    function doPrepare() {
      // 获取当前编辑的文件对象,如果没有打开任何文件,则为空  
      const activeEditor = vscode.window.activeTextEditor;
      if (!activeEditor) {
        return;
      }
    	// 获取编辑文件的文件名
      const activeFilePath = activeEditor.document.fileName;
    	// 业务代码,不用关心
      const result = createValidFileReg().exec(getBasename(activeFilePath));
    
      if (!result) {
        // 弹出警告信息
        vscode.window.showWarningMessage(INVALID_FILE_WARNING_MESSAGE);
        return;
      }
    	// 获取当前 vscode 所打开的工作区目录地址
      const workspaceFilePath = vscode.workspace.getWorkspaceFolder(
        activeEditor.document.uri
      )!.uri.fsPath;
    
      // 省略业务代码
    }
    
    export function activate(context: vscode.ExtensionContext) {
      // 注册 jumpToTest 命令
      const jumpToTestCommand = vscode.commands.registerCommand(
        "find-test-file.jumpToTest",
        () => {
         // 省略业务代码
        }
      );
      // 注册 createTestFile 命令
      const createTestFileCommand = vscode.commands.registerCommand(
        "find-test-file.createTestFile",
        () => {
          // 省略业务代码
        }
      );
      // 将命令注册到执行上下文中
      context.subscriptions.push(jumpToTestCommand, createTestFileCommand);
    }
    
    export function deactivate() {}
    
    

    src/config.ts主要功能:

    • 获取插件配置信息
    // src/config.js
    import vscode from "vscode";
    
    const getCfgByKey = <K1 extends keyof Config, K2 extends keyof Config[K1]>(
      primary: K1,
      key: K2
    ) => {
      // 结合配置,获取用户自定义的配置,获取所有以 findTestFile 开头的配置
      // 前面 configuration 配置中的 properties 各个属性名就是配置的路径, 如 findTestFile.basic.testSuffix
      const config = vscode.workspace.getConfiguration("findTestFile");
    
      // 获取具体某一项配置信息 如 basic.testSuffix
      const cfg = config.get<Config[K1][K2]>(`${primary}.${key}`)!;
      // 通过 inspect 方法获取默认配置,用于垫底
      const defaultCfg = config.inspect<Config[K1][K2]>(`${primary}.${key}`)!
        .defaultValue!;
      return [cfg, defaultCfg];
    };
    
    // 省略业务代码
    

    src/jumpToFile.ts主要功能:

    • 如果找到一个可能的目标文件,直接切换到目标文件
    • 如果找到多个可能的目标文件,需要弹出选择框供用户选择
    import vscode, { QuickPickItem } from "vscode";
    
    export const openFile = async (filePath: string) => {
      // 打开对应地址的文件,注意这个操作是异步的
      const document = await vscode.workspace.openTextDocument(filePath);
      // 将当前窗口切换到该文件,注意这个操作是也异步的
      await vscode.window.showTextDocument(document);
    };
    
    export const jumpToPossibleFiles = async (
      current: string,
      relativeFiles: string[],
      isJumpToTestFile: boolean,
      createTestFileOption: CreateTestFileOption
    ) => {
      
      // 显示选择框,获取用户选择结果,注意这是异步操作
      const select = await vscode.window.showQuickPick(pickItems);
    	// 取消选择时,返回空
      if (!select) {
        return;
      }
      // 省略业务代码
    };
    

    如何开发一款vscode插件

    src/createTestFile.ts主要功能:

    • 如果用户对搜索结果不满意或者未找到测试文件,需要弹出输入框,帮助用户快速新建的测试文件
    import vscode, { QuickPickItem } from "vscode";
    
    export const createTestFile = async (
      { basename, ext, parent, root }: CreateTestFileOption,
      manualCreate: boolean = true
    ) => {
      // 显示输入框
      const userInputPath = await vscode.window.showInputBox({
        prompt: NEW_TEST_FILE_PROMPT,
        value: filePath,
        valueSelection: [filePath.length, filePath.length],
        // 验证输入内容是否合法,返回 null 表示验证成功
        validateInput(value) {
          return isValidFile(basename, ext, value, true)
            ? null
            : INVALID_TEST_FILE_WARNING_MESSAGE;
        },
      });
    	// 取消输入,返回结果为空
      if (!userInputPath) {
        return;
      }
    };
    
    

    如何开发一款vscode插件

    更多 vscode api 使用参见 官方文档。

    发布插件

    啪的一下就写完了代码,很快啊。接下来需要将插件打包发布。

    打包插件需要安装vsce库:

    npm i -g vsce
    

    然后执行打包命令:

    vsce package
    

    打包完成后,会生成find-test-file-x.x.x.vsix文件。此时可以通过插件市场直接安装插件,验证效果:

    如何开发一款vscode插件

    验证完功能的正确性后,就可以真正发布到插件市场:

    1. vscode 的插件市场基于微软的 Azure DevOps,插件的身份验证、托管和管理都是在这里。所以发布前,首先得注册 Azure Devops 账号,就像 npm 一样:

    如何开发一款vscode插件

    1. 注册完成后,创建 Personal Access Token:

    如何开发一款vscode插件

    如何开发一款vscode插件

    复制这个创建好的 token,后续要用。

    1. 接下来还需要在插件市场中 新建一个 publisher 用来发布插件:

    如何开发一款vscode插件

    1. 登录 vsce 账户信息,使用之前注册好的 publisher 以及 token:
    vsce login publisher-name
    

    别忘了在package.json中添加 publisher,icon,categories 等相关信息:

    {
      "publisher": "xxxx",
      "icon": "xxxx/icon.png",
      "categories": [
        "Other"
      ],
    }
    
    1. 登录完成后,就可以愉快的发布啦:
    vsce publish
    

    发布成功后,就可以在插件市场搜索到插件了(通常需要等几分钟),也可以在 网页管理端 查看插件的使用情况。

    如何开发一款vscode插件

    总结

    至此就是笔者在开发插件中所运用到的 vscode 相关知识,希望本文能对你有所帮助,也欢迎大家使用笔者开发的插件和提 issue。


    起源地下载网 » 如何开发一款vscode插件

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元