如何写一个VsCode插件(react-antd-helper的开发纪实)

2022年7月18日 385点热度 0人点赞 0条评论
图片

1背景

每次在开发一个新页面的时候,都要从头开始写一些固定的代码,或者每次在写一些特定场景需求的时候,都要从头开始写需要固定的逻辑功能,而这些工作,都是重复的,而不同的开发者,在实现同一功能时,又表现出五花八门的写法,于是,我决定,写一个工具,用来快速生成常用模板,这不仅对于提升效率有所帮助,对于统一规范也有一定的帮助。当然这个工具可以是 cli 或者 vscode snippets,但个人开发的东西,因为没有太大知名度,使用者主动去用的概率会小一点,于是,我打算开发一个Vscode 插件,接下来就是开发过程。

2开发过程

一、安装脚手架

环境准备

  • NodeJS
  • Git

安装

npm install -g yo generator-code

生成项目框架

yo code

根据脚手架提示选择自己的配置,大概如下图所示

# ? What type of extension do you want to create? New Extension (TypeScript) // 使用语言
# ? What's the name of your extension? react-antd-helper // 插件名称
### Press <Enter> to choose default for all options below ###
# ? What's the identifier of your extension?
# ? What's the description of your extension? 一款快速生成react+antd各种场景的模板插件 // 插件描述
# ? Enable stricter TypeScript checking in 'tsconfig.json'? Yes
# ? Setup linting using 'tslint'? Yes
# ? Initialize a git repository? Yes
# ? Which package manager to use? npm

然后会生成一个“react-antd-helper”的项目,其中主要页面结构如下

|--out // 编译后的输出目录
  |-- extension.js
|--src // 核心逻辑
  |-- extension.ts // 插件内容写在这里
|--package.json // 发布相关的信息都在这里配置
|--CHANGELOG.md // 发布日志

其中,插件的核心功能都会在extension.ts中,当你初始化完一个项目后,该文件的内容大概如下

// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';

// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext{

 // Use the console to output diagnostic information (console.log) and errors (console.error)
 // This line of code will only be executed once when your extension is activated
 console.log('Congratulations, your extension "react-antd-helper" is now active!');

 // The command has been defined in the package.json file
 // Now provide the implementation of the command with registerCommand
 // The commandId parameter must match the command field in package.json
 let disposable = vscode.commands.registerCommand('react-antd-helper.helloWorld'() => {
  // The code you place here will be executed every time your command is executed
  // Display a message box to the user
  vscode.window.showInformationMessage('Hello World from react-antd-helper!');
 });
 context.subscriptions.push(disposable);
}

// this method is called when your extension is deactivated
export function deactivate({}

这里最主要的内容就是

 let disposable = vscode.commands.registerCommand('react-antd-helper.helloWorld', () => {
        // The code you place here will be executed every time your command is executed
        // Display a message box to the user
        vscode.window.showInformationMessage('Hello World from react-antd-helper!');
    });

注册了一个指令react-antd-helper.helloWorld,然后做了一个回调。我们可以在里面写我们自己的逻辑,这里我先不冗余写了,不同的插件实现方式也不一样,我会先文章结尾附上我个人插件的源码。

调试

我们直接点击 VsCode 调试按钮Run Extension进行调试即可,这时会打开一个新的窗口Extension Development Host(你打开的文件夹),然后就可以在这个页面进行调试了

图片

同时,也可以在新打开的页面,输入command + shift + P看到我们注册的指令,并执行测试

图片

发布配置

对于 VsCode 插件来说,插件内容比较灵活,开发内容没有太固定的形式,这里我们就不细说了,而其发布配置,有好多重要的点也是比较通用的点,比较重要,下面我们详细介绍一下发布配置package.json

{
    "name""react-antd-helper",
 "displayName""react-antd-helper",  // // 展示名称
 "description""一款快速生成react+antd各种场景的模板插件", // 插件描述
 "version""0.0.7", // 插件版本,可以自己修改,也可以在发布时自动改,生成的插件包会带这个版本
 "repository""https://github.com/sorryljt/react-antd-helper",// 仓库地址
 "publisher""sorryljt", // 发布者
 "license""MIT",
 "icon""logo.png", // 在插件市场展示的插件logo,这里得是一个相对路径的地址
 "engines": {
  "vscode""^1.65.x" // 适配的vscode版本,版本过高,将导致低版本vscode安装失败
 },
 "categories": [
  "Other"
 ],
 "activationEvents": [ // 所有的插件中的指令要在这里注册
     "onCommand:react-antd-helper.helloWorld",
        "onCommand:react-antd-helper.generateSimplePage",
        "onCommand:react-antd-helper.generateSearchFormAndTable",
        "onCommand:react-antd-helper.generateModal"
 ],
 "main""./out/extension.js", // 入口文件
 "contributes": {
  "commands": [ // 指令的详情,可以在 `command` + `shift` +   `P`时看到
   {
    "command""react-antd-helper.generateSimplePage",
    "title""生成一个简单页面",
    "category""快速生成React&Antd页面"
   },
   {
    "command""react-antd-helper.generateSearchFormAndTable",
    "title""生成一个表单检索&表格页面",
    "category""快速生成React&Antd页面"
   },
   {
    "command""react-antd-helper.generateModal",
    "title""生成一个弹窗页面",
    "category""快速生成React&Antd页面"
   }
  ],
  "menus": { // 菜单配置
            "explorer/context": [ // 文件夹菜单
    {
                    "group""2_workspace@1",// 决定排序方式,可参考https://www.bookstack.cn/read/VS-Code-Extension-Doc-ZH/docs-extensibility-reference-contribution-points.md#4hamih
                    "when""explorerResourceIsFolder", // 执行时机 可参考https://liiked.github.io/VS-Code-Extension-Doc-ZH/#/references/when-clause-contexts
     "submenu""react-antd-helper/submenu/generate" // 可以设置该菜单为子菜单
                 }
            ],
   "react-antd-helper/submenu/generate": [ // 对应id的子菜单配置,在这里可以配置其对应的指令和排序
    {
     "command""react-antd-helper.generateSimplePage",
     "group""1_generate@1"
    },
    {
     "command""react-antd-helper.generateSearchFormAndTable",
     "group""1_generate@2"
    },
    {
     "command""react-antd-helper.generateModal",
     "group""1_generate@3"
    }
   ]
        },
  "submenus": [ // 子菜单的配置,以及其标题显示
   {
    "id""react-antd-helper/submenu/generate",
    "label""快速生成一个react&antd页面"
   }
  ]
 },
 "scripts": {
  "vscode:prepublish""yarn run compile",
  "compile""tsc -p ./",
  "watch""tsc -watch -p ./",
  "pretest""yarn run compile && yarn run lint",
  "lint""eslint src --ext ts",
  "test""node ./out/test/runTest.js"
 },
 "devDependencies": {
  "@types/vscode""^1.65.0",
  "@types/glob""^7.2.0",
  "@types/mocha""^9.1.1",
  "@types/node""16.x",
  "@typescript-eslint/eslint-plugin""^5.30.0",
  "@typescript-eslint/parser""^5.30.0",
  "eslint""^8.18.0",
  "glob""^8.0.3",
  "mocha""^10.0.0",
  "typescript""^4.7.4",
  "@vscode/test-electron""^2.1.5"
 }
}

在上述的package.json文件介绍中,大部分我通过标记注释的方式来说明用法,这里再特殊说明一下我在开发时候,踩过坑的几个配置项

  • contributes.commands中注册的指令,要在src/extension.ts中实现,反之,在src/extension.ts中实现的指令,也要在其中注册
  • 定义指令后,还需要在activationEvents中激活"onCommand:react-antd-helper.helloWorld"
  • 菜单的配置,我们大部分配置可以官网发布配置[1]中找到,但是其中并没有提起对于资源管理器上下文菜单的子菜单配置,我是通过看其他插件的开发代码找到了配置方法,就像我设置的submenus那种
  • 关于 logo 的配置,找了很久,因为默认是不带 logo 的,并且发布配置中也没有介绍,后来找到了这里https://www.bookstack.cn/read/VS-Code-Extension-Doc-ZH/docs-references-extension-manifest.md

发布插件

插件发布官网提供了比较全的教程,这里做个总结,具体发布看这两篇官网链接就够了

  • https://code.visualstudio.com/api/working-with-extensions/publishing-extension#get-a-personal-access-token
  • https://www.bookstack.cn/read/VS-Code-Extension-Doc-ZH/docs-working-with-extensions-publish-extension.md
安装 vsce
npm install -g vsce
打包成 vsix 文件
vsce package
发布

发布之前,首先你得有一个Personal Access Tokens[2]按照上面的文档,创建完,可以采用

vsce publish

也可以采用可视化上传 vsix 文件的方式来发布

图片

发布成功后就可以在扩展市场看到自己的插件了。

遇到的问题

  • windows 系统文件反斜杠的问题
    因为我的插件是需要写入文件的,我当时用的是的 mac 开发,当有些同学试用的时候,发现写入文件失败,后来才发现,我忽略了 windows 系统下文件路径“\”反斜杠的问题。

  • 不能使用 node 原生 path 来获取命令操作路径,在 vscode 开发环境中,我们不能使用 path 中的__dirname以及path.resolve(./)来获取操作路径,应该使用registerCommand方法的回调参数,如下

 let generateModal = vscode.commands.registerCommand('react-antd-helper.generateModal', (e) => {
  console.log(e) // 其中e为文件信息,但e.fsPath才代表不同操作系统下的真实路径
 });

其中 e 为文件信息,但 e.fsPath 才代表不同操作系统下的真实路径,所以在拼接文件名时要使用e.faPath,并且拼接符号的正反斜杠,要使用 node path 下的sep变量。这样就可以自动区分出不同系统下的文件路径了,最终可以是这样拼写${fsPath}${nodepath.sep}index.tsx

3总结

本文介绍了我个人开发的一个 vscode 插件的历程,另外也欢迎大家使用我的 vscode 插件,功能如下
安装了插件后(react-antd-helper),在文件夹处鼠标右击,即可出现如下的菜单

图片

点击生成需要的页面,即可生成例如下面的较完整,可运行的 react 代码

图片

欢迎大家使用哦!

也欢迎大家共建,本插件的源码如下

https://github.com/sorryljt/react-antd-helper

参考资料

[1]

官网发布配置: https://www.bookstack.cn/read/VS-Code-Extension-Doc-ZH/docs-extensibility-reference-contribution-points.md

[2]

Personal Access Tokens: https://docs.microsoft.com/azure/devops/integrate/get-started/authentication/pats

69300如何写一个VsCode插件(react-antd-helper的开发纪实)

这个人很懒,什么都没留下

文章评论