前端利器躬行记(8)——VSCode插件研发
VSCode提供了丰富的 API,可以借助编辑器扩展许多定制功能。
本次研发了一款名为 Search Method 的插件,在此记录整个研发过程。
一、准备工作
1)安装环境
首先是全局安装 yo 和 generator-code 两个库,我本地全局安装了 cnpm,所以用它来安装。
npm install yo generator-code -g

yo code
回答些问题,但如果在回答 Initialize a git repository 时选择 yes,那么就会出现报错。
|-- test
|-- extension.js // 插件入口文件,插件的逻辑在此完成
|-- CHANGELOG.md
|-- package-lock.json
|-- package.json
|-- README.md // 插件说明 README,发布后会展示
|-- jsconfig.json
|-- .eslintrc.json
|-- vsc-extension-quickstart.md
最重要的就是 extension.js 和 package.json,前者会实现插件的核心功能,后者包括插件的配置信息。
2)调试
选择 run =》 Start Debugging 后,就会自动弹出另一个 VSCode 窗口。
在这个窗口中,会默认安装上正在调试的插件,其实我本来起的插件名字叫 Search Function。
但是在调试时,按下 Command + Shift + P 打开命令面板,却无法在此处找到默认的 Hello World 命令。
直到我换了名字后,才能在调试时找到 Hello World,这个坑也花了我好几个小时。
还有个问题,就是在在编辑器的 Debug Console 标签内无法看到打印信息,相当于是在盲调,电脑重启后,就能看到了,还是重启大法好。
至此,完成了整个准备工作。
二、开发过程
公司有个 Node 项目,现在有个问题,就是 router 层的代码无法自动关联到 service 层的方法声明。
下面这段代码存在于 router 层,common 存在于service 层,它有一个 aggregation() 方法。
原先鼠标拖到方法处,按住 command 键,就能跳转到声明处,查看方法实现逻辑,但是现在无法跳转。
const data = await services.common.aggregation({ tableName });
因为项目为了不用每次初始化 service 中的类,一下子全部都初始化好了,赋到一个对象中,如下所示。
Object.keys(dir).forEach((item) => {
services[item] = new dir[item](models);
});
这次要开发的插件,其实就是为了解决此问题,提升大家的开发效率。
1)最终效果
在经过多轮深思熟虑的设计之后,确定了要达到的效果,那就是先选中要查看的方法以及文件名称,然后右键找到 Search Services File 菜单,此时就能直接跳转过去了。

2)菜单配置
要想在右键显示这个自定义的菜单,需要在 package.json 中做些配置。
commands 是默认就存在的,主要是 menus 字段,注册菜单。
"contributes": {
"commands": [
{
"command": "search-method.services",
"title": "Search Services File"
}
],
"menus": {
"editor/context": [
{
"command": "search-method.services",
"group": "navigation",
"when": "editorHasSelection"
}
]
}
},
editor/context 是指编辑器上下文菜单,在 contributes.menus 一栏中,还可以找到其余 menus 的关键字,可以都尝试下。
editor/context 的值是一个数组,可以配置多个菜单,菜单中的 group 就是菜单所处的位置。
navigation 就是最上面,还有 1_modification,9_cutcopypaste 和 z_commands 参考下图。
when 就是触发条件,editorHasSelection 就是指在编辑器中选中时触发。
可选的关键字还可以是 editorFocus、inputFocus、editorHasMultipleSelections 等,参考 available contexts。
下面这段就是最精简的 extension.js 代码了,注册一个名为 search-method.services 的命令,核心功能会在此回调函数中实现。
const vscode = require('vscode');
function activate(context) {
const disposable = vscode.commands.registerCommand(
'search-method.services', (uri) => {
}
context.subscriptions.push(disposable);
}
function deactivate() {}
module.exports = {
activate,
deactivate
}
在研发时,以为像下面这样就能直接得到 webMonitor.js 绝对目录,但其实此处读的是插件的根目录,而不是项目的。
path.resolve(__dirname, '../services/webMonitor.js')
通过回调函数的参数 uri.fsPath 才能得到当前选中的代码所处的绝对位置。下面是完整的插件逻辑。
1 const vscode = require('vscode');
2 const path = require('path');
3 const fs = require('fs');
4 const { Uri, window, Position, Range, Selection } = vscode;
5 const disposable = vscode.commands.registerCommand(
6 "search-method.services",
7 (uri) => {
8 // 获取编辑器对象
9 const editor = window.activeTextEditor;
10 if (!editor) {
11 return;
12 }
13 // 当前选中的代码所处的绝对位置
14 const dirPath = uri.fsPath;
15 // services的绝对目录
16 const serviceDir = path.resolve(dirPath, "../../services");
17 // 获取选中文本
18 const doc = editor.document;
19 const selection = editor.selection;
20 const words = doc.getText(selection).split(".");
21 const serviceName = words[0];
22 const methodName = words.length > 1 ? words[1] : "";
23 // 列出目录中所有的文件
24 const files = fs.readdirSync(serviceDir);
25 for (const item of files) {
26 // 读取文件名称
27 const name = item.split(".")[0];
28 // 文件匹配
29 if (serviceName === name) {
30 const file = Uri.file(path.resolve(serviceDir, item));
31 // 根据换行符分隔字符串
32 const fileContentArr = fs
33 .readFileSync(path.resolve(serviceDir, item), "utf8")
34 .split(/\r?\n/);
35 // 声明的方法会有 async 关键字,或者通过空格和括号匹配
36 const index = fileContentArr.findIndex(
37 (element) =>
38 element.indexOf(`async ${methodName}`) >= 0 ||
39 element.indexOf(` ${methodName}(`) >= 0
40 );
41 // 跳转到指定行数的文件
42 window.showTextDocument(file).then((editor) => {
43 // 开始位置
44 const start = new Position(index, 0);
45 // 结束位置加了 20 行,为了便于查看
46 const end = new Position(index + 20, 0);
47 // 光标聚焦的位置
48 editor.selections = [new Selection(start, start)];
49 // 可见范围
50 const range = new Range(start, end);
51 editor.revealRange(range);
52 });
53 break;
54 }
55 }
56 }
57 );
- 第13行,读取当前项目 services 的绝对路径。
- 第17行,获取选中的文本,例如 common.aggregation,然后分隔得到文件名和方法名。
- 第23行,列出 services 的所有文件,并与选中的文件名匹配。
- 第28行,匹配成功时读取文件内容并通过换行符分隔,查找方法所在的行。
- 第41行,通过 window.showTextDocument 打开 Uri.file() 处理过的文件,初始化 Position 类,配置光标聚焦的位置(Selection)和可见范围(Range)。
虽然只有40多行代码,但花费了我一天的时间才完成,中间走了不少弯路,最麻烦的是跳转文件,showTextDocument() 方法也是偶然间才发现的。
还有个小技巧,可以通过看 window、Uri 这些类的声明,就能了解到它们提供的功能。
三、对外发布
为了能在 VSCode 的 Extensions 中被搜索到,还需要几个步骤。
1)注册账号
首先到 Azure DevOps 创建管理账号,根据提示来就行了。
然后选中 Personal access tokens,去创建 token。

接着在创建时,有些选项要注意,Organization 和 Scopes,网上说不能乱选,否则发布会不成功。创建后,记得自己将 token 保存一下,后面就无法查看了。
最后创建发布账号,填些信息,下一步登录时使用。
vsce 用于上传插件,首先全局安装。
npm i vsce -g
然后是登录刚刚注册的发布账号,例如 vsce login pwstrick。
vsce login <publisher name>
选好后会要求你输入之前申请的 token,登录成功后就会有下面的一段提示。
Personal Access Token for publisher 'pwstrick': ************************
The Personal Access Token verification succeeded for the publisher 'pwstrick'.
此时,就可以输入发布命令了,成功的话,就会出现 DONE 的提示。
vsce publish INFO Publishing 'pwstrick.search-method v0.0.1'...
INFO Extension URL (might take a few minutes): https://marketplace.visualstudio.com/items?itemName=pwstrick.search-method
INFO Hub URL: https://marketplace.visualstudio.com/manage/publishers/pwstrick/extensions/search-method/hub
DONE Published pwstrick.search-method v0.0.1.
上传成功后,不会马上就能搜索到。
在插件管理中,当出现绿色的勾时,才表示插件发布完成,现在可以在应用市场搜索到了。

可以看到并不是在第一行,需要往下翻一翻。

在给组员使用时,发现他们不能安装,因为我设置的最低版本是 1.7.0,这个在开发的时候也需要注意。
"engines": {
"vscode": "^1.70.0"
},
前端利器躬行记(8)——VSCode插件研发的更多相关文章
- 前端利器躬行记(2)——Babel
Babel是一个JavaScript编译器,不仅能将当前运行环境不支持的JavaScript语法(例如ES6.ES7等)编译成向下兼容的可用语法(例如ES3或ES5),这其中会涉及新语法的转换和缺失特 ...
- 前端利器躬行记(3)——webpack基础
webpack是一个静态模块打包器,此处的模块可以是任意文件,包括Sass.TypeScript.模板和图像等.webpack可根据输入文件的依赖关系,打包输出浏览器可识别的JavaScript.CS ...
- 前端利器躬行记(4)——webpack进阶
webpack是一个非常强大的工具,除了前文所介绍的基础概念之外,还有各种进阶应用,例如Source Map.模块热替换.集成等,本文会对这些内容做依次讲解. 一. runtime和manifest ...
- 前端利器躬行记(6)——Fiddler
Fiddler是一款免费的.基于Windows系统的代理服务器软件(即Web调试抓包工具),由Eric Lawrence用C#语言在2003年10月发布了第一个版本.注意,由于Fiddler依赖Mic ...
- 前端利器躬行记(1)——npm
npm(Node Package Manager)是Node.js的包管理工具,相当于一个在线仓库.它提供了一个公共的平台,将分散在世界各地的包集中起来,能轻松的安装.分享和管理相关的包,不用再为搜索 ...
- 前端利器躬行记(5)——Git
Git是一款开源的分布式版本控制系统,它的出现和Linux紧密相关.Linux内核项目组为了能更好地管理和维护Linux内核开发,于2002年开始启用商业的分布式版本控制系统BitKeeper.虽然软 ...
- ES6躬行记(1)——let和const
古语云:“纸上得来终觉浅,绝知此事要躬行”.的确,不管看了多少本书,如果自己不实践,那么就很难领会其中的精髓.自己研读过许多ES6相关的书籍和资料,平时工作中也会用到,但在用到时经常需要上搜索引擎中查 ...
- ES6躬行记 笔记
ES6躬行记(18)--迭代器 要实现以下接口## next() ,return,throw 可以用for-of保证迭代对象的正确性 例如 var str = "向
- Node.js躬行记(9)——微前端实践
后台管理系统使用的是umi框架,随着公司业务的发展,目前已经变成了一个巨石应用,越来越难维护,有必要对其进行拆分了. 计划是从市面上挑选一个成熟的微前端框架,首先选择的是 icestark,虽然文档中 ...
随机推荐
- vue大型电商项目尚品汇(后台篇)day02
这几天更新有点小慢,逐渐开始回归状态了.尽快把这个后台做完,要开始vue3了 3.添加修改品牌 用到组件 Dialog 对话框,其中visible.sync这个配置是修改他的显示隐藏的,label-w ...
- 【RocketMQ】Broker服务注册
Broker注册 在Broker的启动函数中,添加了定时向NameServer进行注册的任务,在启动后延迟10秒向NameServer进行注册,之后定时发送心跳包,关于发送周期,首先从Broker配置 ...
- UML之顺序图(时序图)
1 顺序图 1.1 顺序图的概念 顺序图(sequence diagram): 用来描述为了完成确定事务,对象之间按照时间消息交互的顺序关系. 1.2 顺序图样式和元素 (1) 对象及命名 (2) 生 ...
- Linux操作系统(4):磁盘分区、挂载
Outline: ① lsblk :查看所有设备挂载情况 ② df -h :查询系统整体磁盘使用情况 ③ du -h /目录 :查询指定目录的磁盘占用情况 ④ mount :查询系统中已经挂载的设备 ...
- 常用API(Java)
常用API Object toString方法 场景:当我们使用toString方法想要输出对象变量时,官方提供的toString方法会直接输出对象所在的地址,而不是我们想要的对象变量,所以我们要把t ...
- CTO与CIO选型数据中台的几大建议
企业数字化转型离不开企业数字化技术的配备.但企业在选择数字化技术时也面临着一个问题,就是如何在大胆采用先进的数字化技术和对技术进行投资之间找到平衡,将投资风险降到最低,毕竟错误的技术选型会给企业带来不 ...
- Python中使用 for 循环来拿遍历 List 的值
常规版本 简单的 for 循环遍历 x_n = ["x1","x2","x3"] for x in x_n: print(x) >&g ...
- 如何做出一个好的c++游戏
目录 一.游戏分类 1.文字型 2.画图型 3.键盘型 二.游戏创意 你的程序可以比较激情.热血 1.打怪,爆装备型 2.答题闯关型 可以添加一些不可思议的物品和玩法 三.学号c++/c的语法,是成功 ...
- 不是第七代的 Win 7
贡献者:历史上的今天 Windows 7 是由微软公司(Microsoft)2009 年 10 月 22 日发布的桌面端操作系统,它影响了每个行业的方方面面,以至于很多人仍然在日常生活和工作中使用它. ...
- 如何在CentOS上找出逐渐耗尽磁盘空间的目录和文件
起因 随着系统运行,CentOS空间不断减少,对此非常焦虑,到底磁盘空间被哪些新增文件占用了呢? 分析过程,主要使用du命令,逐层找出消耗空间的目录 1.在根目录下检索一下文件的占用情况,执行du命令 ...