背景
好久不见,整了一个月的Electron+React+Node实现项目辅助工具
好不容易搞完了,然后在项目组里推广,经过一周在团队内部使用,使用效果并不理想,无人问津,经过反馈,原因在于组员更多操作还是在 vscode 中完成, 这就很蛋疼了,都是给 vscode 惯的,好家伙,向 vscode 低头,于是我尝试这个项目辅助工具做到 vscode 插件中~
⚠️ 请注意:这篇文章是说明在开发 vscode 插件时的一些坑以及 demo 的例子,至于Electron+React+Node实现项目辅助工具
系列文章在准备中,还有最终实践落地的 vscode 实战插件文章也躺在草稿箱里
吐槽一下
我怀疑我是被“搞”了,本来这个项目辅助工具使用 Electron
开发时,我就觉得这是个坑,毕竟我没写过 electron,等我做完了之后,好家伙,跟我说:“还需要下载个 PC 包安装,再运行应用?”,“操作繁琐”,让我做个 vscode 插件
vscode 插件我也没搞过啊,这是让我“迎难(男)而上”了!好了,废话不多说,直接开始吧。 怎么说呢,在做之前,也在网上搜过一些文章,奈何大部分都停留在 install + hello world 阶段,意思就是教你如何安装,然后写一个 hello world 简单的小 demo,当然,这也没问题,但这并不是我想要的,我想要的是需要各种场景下的 demo 例子,经过一些文章的查找和翻阅官方文档,整理了一些常见的例子,后续会持续更新,包括项目最终落地的 vscode 实战插件等~
初步尝试
一、安装依赖
微软为了造福大众,提供了一个 yeoman
脚手架,通过此脚手架可以生成开发插件的模版代码。可以通过命令进行安装
npm install -g yo generator-code
这时候你应该是有以下环境的
- nodejs
- npm
- yeoman
- generator-code
二、初始化 Demo 插件
当上面的安装完毕之后,只需要进入你开发目录文件夹,通过脚手架生成一个开发 vscode 插件的项目。
yo code
根据提示信息填写相关内容
这时候我们的 vscode 插件项目就完成初始化了~ 下面看看相关文件的说明!
文件说明
项目中两个重要的文件我们需要看一下:extension.ts 和 package.json
3.1 extension.ts
该文件是入口文件,下面我们写一段简单的 demo 代码
此段代码意思为:注册一个 beehive.toastDemo 事件,当触发此事件会显示一段 message
// extension.ts
import * as vscode from 'vscode'
export function activate(context: vscode.ExtensionContext) {
console.log('your extension "sugar-demo-vscode" is now active!')
let disposable = vscode.commands.registerCommand('beehive.toastDemo', () => {
vscode.window.showInformationMessage('toastDemo touched !')
})
context.subscriptions.push(disposable)
}
export function deactivate() {}
3.2 package.json
该文件配置项太多,建议去官方文档翻阅
关键的主要是: activationEvents 和 contributes 这两个属性,关于这两个属性你可以看官方文档
下面讲一下 contributes 这玩意,contributes 是这个插件的核心,指代这个插件有哪些功能。通过官方文档我们也能知道(这些都在demo 例子中有写到):
- configuration:通过这个配置项我们可以设置一个属性,这个属性可以在 vscode 的 settings.json 中设置,然后在插件工程中可以读取用户设置的这个值,进行相应的逻辑。
- commands:定义的命令,在 vscode 中通过
cmd+shift+p
进行输入定义好的命令就可触发对应事件。 - menus:自定义编辑器右侧菜单栏
- keybindings:可以设置快捷键
- languages:设置语言特点,包括语言的后缀等
- grammars:可以在这个配置项里设置描述语言的语法文件的路径,vscode 可以根据这个语法文件来自动实现语法高亮功能
- snippets:设置语法片段相关的路径
以上边注册的 toastDemo
为例,此时的 package.json 应为:
{
"activationEvents": ["onCommand:beehive.toastDemo"],
"contributes": {
"commands": [
{
"command": "beehive.toastDemo",
"title": "demo1: beehive.toastDemo !"
}
]
}
}
四、运行 vscode 插件
点击此 Debug Icon,或者是 vscode 菜单栏:Run -> Start Debugging

当我们点击下 Run Extension 时,会开一个本地 vscode 窗口

我们在新开的 vscode 窗口中输入 : cmd + shift + P

然后输入我们注册的事件:beehive.toastDemo
,然后我们按下回车,就会执行我们写的事件回调了!

至此,我们的第一个简单 Demo 完成!如果你还不了解,? 建议直接去看源码,特别简单
例子
我写个 vscode 插件,肯定不只是想展示一个 toastMessage
弹窗吧 ???我想做些交互效果咋办,想自定义 Menu、想展示 WebView、想自定义左侧侧边栏咋整??不慌,往下看,下面是我整理的一些小 demo,虽然不一定能满足你的需求,但是希望应该能给你一些帮助~
1.输入内容(Input)
场景
该场景适合一些需要输入内容之后做的操作;
- 输入 text ,发起接口请求等
- 输入 text ,执行一些逻辑操作
- ......
代码展示
// demo1 需要Input输入内容
// beehive-inputName.ts
import * as vscode from 'vscode'
module.exports = function (context: vscode.ExtensionContext) {
let disposable = vscode.commands.registerCommand('beehive.inputName', () => {
vscode.window
.showInputBox({
ignoreFocusOut: true,
password: false,
prompt: 'entry your name',
})
.then((value) => {
if (value === undefined || value.trim() === '') {
vscode.window.showInformationMessage('Please type your name.')
} else {
const name = value.trim()
vscode.window.showInformationMessage('your name is: ', name)
return
}
})
})
context.subscriptions.push(disposable)
}
入口文件需要引入该文件
// extension.ts
import * as vscode from 'vscode'
export function activate(context: vscode.ExtensionContext) {
console.log('your extension "sugar-demo-vscode" is now active!')
require('./beehive-inputName')(context) // demo1 输入Input内容
}
export function deactivate() {}
通过 package.json 也需要注册此事件
{
"activationEvents": ["onCommand:beehive.inputName"],
"contributes": {
"commands": [
{
"command": "beehive.inputName",
"title": "demo1: beehive.inputName !"
}
]
}
}
效果展示

源码展示
- beehive-inputName.ts
2.自定义 WebView 页面
场景
该插件场景适合做一些简单页面展示、欢迎页面等
代码展示
// demo2 自定义显示页
// 具体看 package.json 中的 configuration 和 commands
import * as vscode from 'vscode'
import * as fs from 'fs'
import * as path from 'path'
module.exports = function (context: vscode.ExtensionContext) {
let disposable = vscode.commands.registerCommand(
'beehive.customWelcome',
() => {
const panel = vscode.window.createWebviewPanel(
'welcome',
'自定义欢迎页',
vscode.ViewColumn.One,
{
enableScripts: true,
}
)
const htmlPath = path.join(
context.extensionPath,
'src/customWelcome.html'
)
let html = fs.readFileSync(htmlPath, 'utf-8')
panel.webview.html = html
}
)
context.subscriptions.push(disposable)
}
// extension.ts
import * as vscode from 'vscode'
export function activate(context: vscode.ExtensionContext) {
console.log('your extension "sugar-demo-vscode" is now active!')
require('./beehive-customWelcome')(context) // demo2 加载自定义WebView欢迎页
}
export function deactivate() {}
// package.json
{
"activationEvents": ["onCommand:beehive.customWelcome"],
"contributes": {
"commands": [
{
"command": "beehive.customWelcome",
"title": "demo4: beehive.customWelcome !"
}
]
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>自定义欢迎页面</title>
<style>
.app {
margin: 12px 0;
font-size: 24px;
}
.title {
font-size: 18px;
margin-top: 24px;
}
</style>
</head>
<body>
<div class="app">
Welcome BeeHiver ~
<div class="title">后人哀之而不鉴之 亦使后人而复哀后人也 !</div>
</div>
<img
src="https://media.giphy.com/media/JIX9t2j0ZTN9S/giphy.gif"
width="300"
/>
</body>
</html>
效果展示

源码展示
- beehive-customWelcome.ts
3.快捷键注册
场景
每次我们都需要 cmd+shift + P 调出选择器,然后输入我们注册的事件名,特别麻烦,vscode 支持快捷键注册,下面看看如何实现吧!
代码展示
{
"activationEvents": ["onCommand:beehive.keybindings"],
"contributes": {
"commands": [
{
"command": "beehive.keybindings",
"title": "demo4: beehive.keybindings !"
}
],
"keybindings": [
{
"command": "beehive.keybindings",
"key": "Cmd+]",
"mac": "Cmd+]",
"when": "editorTextFocus"
}
]
}
}
然后此时我们通过 Run Extension
(上面有说如何运行插件) ,在本地窗口,我们随便打开一个文件,然后按下 : cmd+]
就可以触发我们定义的 beehive.keybindings
事件
源码展示
- beehive-keybindings.ts
4.自定义菜单 Menu
场景
适用于一些快捷按钮的自定义,可通过 Menu 操作
代码展示
// demo4 自定义菜单
import * as vscode from 'vscode'
module.exports = function (context: vscode.ExtensionContext) {
let disposable = vscode.commands.registerCommand('beehive.customMenu', () => {
vscode.window.showInformationMessage("I' am custom menu !")
})
context.subscriptions.push(disposable)
}
// extension.ts
import * as vscode from 'vscode'
export function activate(context: vscode.ExtensionContext) {
console.log('your extension "sugar-demo-vscode" is now active!')
require('./beehive-customMenu')(context) // demo4 自定义菜单
}
export function deactivate() {}
// package.json
{
"activationEvents": ["onCommand:beehive.customMenu"],
"contributes": {
"commands": [
{
"command": "beehive.customMenu",
"title": "demo5: 启动自定义菜单"
}
],
"menus": {
"editor/title": [
{
"command": "beehive.customMenu",
"alt": "beehive.customMenu",
"group": "navigation"
}
]
}
}
}
关于这些字段信息,我就不一一贴了,官方文档很多说明,直接看这里: ? 文档相关字段说明
效果展示

点击之后,触发事件

源码展示
- beehive-customMenu.ts
5.悬停提示
场景
当你鼠标光标 hover 至某个代码时,你想要显示一些文字内容
代码展示
// demo5 对package.json中的author进行悬停提示
import * as vscode from 'vscode'
module.exports = function (context: vscode.ExtensionContext) {
let disposable = vscode.languages.registerHoverProvider('json', {
provideHover(document, position, token) {
const fileName = document.fileName
const word = document.getText(document.getWordRangeAtPosition(position))
if (/\/package\.json$/.test(fileName) && /\bauthor\b/.test(word)) {
return new vscode.Hover('悬停提示: 彭道宽牛逼!')
}
return undefined
},
})
context.subscriptions.push(disposable)
}
上面对于文件以及关键词 keyword 可以根据业务自行抽离,这里就不写那么多,自行领悟~
// extension.ts
import * as vscode from 'vscode'
export function activate(context: vscode.ExtensionContext) {
console.log('your extension "sugar-demo-vscode" is now active!')
require('./beehive-hoverTips')(context) // demo5 悬停提示
}
export function deactivate() {}
效果展示
源码展示
- beehive-hoverTips.ts
6.代码片段
场景
输入一个前缀,会得到一个或多个提示,然后回车带出很多代码。
代码展示
需要修改 package.json 中的 snippets 的配置
// package.json
{
"contributes": {
"snippets": [
{
"language": "html",
"path": "./src/snippets/html.json"
}
]
}
}
然后添加一个 html.json 配置
{
"PDK": {
"prefix": ["PDK", "PD", "PK", "DK"],
"body": ["<PDK>", "${1}", "</PDK>"],
"description": "彭道宽自定义的snippets"
}
}
关于每个字段,可以通过官方文档了解:create-your-own-snippets
上面我们是设置语言为 : html,所以在运行插件,并保证插件被激活,在规定的语言 html 中,输入 prefix 相关的关键词,就可以啦
效果展示


源码展示
- snippets 中的 package 配置
7.自定义侧边栏+面板
背景
需要在左侧自定义侧边栏,完成一些交互逻辑操作
代码实现
⚠️ 需要注意:侧边栏按钮(Tree View Container)和面板视图(Tree View)要同时配置,否则不生效
侧边栏的展示
首先,我们先看官方文档,看看如何在左边这个侧边栏添加我们自定义的内容
? contribution-points#contributes.viewsContainers
// package.json
{
"contributes": {
"viewsContainers": {
"activitybar": [
{
"id": "sugar",
"title": "Sugar-BeeHive",
"icon": "./src/logo/sugar.svg"
}
]
},
"views": {
"sugar": [
{
"id": "BeeHive-Command",
"name": "01.命令集"
},
{
"id": "BeeHive-PackageAnalysis",
"name": "02.包分析"
}
]
}
}
}
⚠️ 注意点:views 中 key 要和 activitybar 中的属性 id 保持一致,如 sugar 在两者中是一致的
这时候运行我们的插件:Run Extension
,就可以看到在左侧有我们自定义的侧边栏啦

上面我们配置完 package.json
之后,我们再回到文档,会看到这么一段话:tree-view#activationEvents
如果需要,你就加上下面这段代码即可
{
"activationEvents": ["onView:BeeHive-Command"]
}
如何定义面板内容
上面是展示出来了侧边栏,但是我们需要展示内容啊,怎么整?通过官方文档:tree-data-provider 可以实现一个小 demo,下面这段代码也是基于官方文档改的
// beehive-sidebar.ts
// demo7 自定义侧边栏入口和面板
import * as vscode from 'vscode'
const scripts = [
{
script: 'webpack:dev',
},
{
script: 'webpack:prod',
},
{
script: 'server:dev',
},
{
script: 'server:test',
},
{
script: 'server:test-1',
},
{
script: 'server:test-2',
},
]
/**
* @description 重写每个节点
*/
export class SideBarEntryItem extends vscode.TreeItem {
constructor(
private version: string,
public readonly label: string,
public readonly collapsibleState: vscode.TreeItemCollapsibleState
) {
super(label, collapsibleState)
this.tooltip = `${this.label}-${this.version}`
// this.description = `${this.version}-${Math.ceil(Math.random() * 1000)}`
}
}
/**
* @description 入口文件
*/
export class SideBarBeeHiveCommand
implements vscode.TreeDataProvider<SideBarEntryItem> {
constructor(private workspaceRoot?: string) {}
getTreeItem(element: SideBarEntryItem): vscode.TreeItem {
return element
}
getChildren(
element?: SideBarEntryItem
): vscode.ProviderResult<SideBarEntryItem[]> {
if (element) {
//子节点
var childrenList = []
for (let index = 0; index < scripts.length; index++) {
var item = new SideBarEntryItem(
'1.0.0',
scripts[index].script,
vscode.TreeItemCollapsibleState.None
)
item.command = {
command: 'BeeHive-Command.openChild', //命令id
title: scripts[index].script,
arguments: [scripts[index].script], //命令接收的参数
}
childrenList[index] = item
}
return childrenList
} else {
//根节点
return [
new SideBarEntryItem(
'1.0.0',
'项目一',
vscode.TreeItemCollapsibleState.Collapsed
),
new SideBarEntryItem(
'1.0.0',
'项目二',
vscode.TreeItemCollapsibleState.Collapsed
),
]
}
}
}
export class SideBarBeeHivePackageAnalysis
implements vscode.TreeDataProvider<SideBarEntryItem> {
constructor(private workspaceRoot?: string) {}
getTreeItem(element: SideBarEntryItem): vscode.TreeItem {
return element
}
getChildren(
element?: SideBarEntryItem
): vscode.ProviderResult<SideBarEntryItem[]> {
if (element) {
//子节点
var childrenList = []
for (let index = 0; index < scripts.length; index++) {
var item = new SideBarEntryItem(
'1.0.0',
scripts[index].script,
vscode.TreeItemCollapsibleState.None
)
item.command = {
command: 'BeeHive-PackageAnalysis.openChild', //命令id
title: scripts[index].script,
arguments: [index], //命令接收的参数
}
childrenList[index] = item
}
return childrenList
} else {
//根节点
return [
new SideBarEntryItem(
'1.0.0',
'按钮组',
vscode.TreeItemCollapsibleState.Collapsed
),
]
}
}
}
module.exports = function (context: vscode.ExtensionContext) {
// 注册侧边栏面板
const sidebarBeeHiveCommand = new SideBarBeeHiveCommand()
const sidebarBeeHivePackageAnalysis = new SideBarBeeHivePackageAnalysis()
vscode.window.registerTreeDataProvider(
'BeeHive-Command',
sidebarBeeHiveCommand
)
vscode.window.registerTreeDataProvider(
'BeeHive-PackageAnalysis',
sidebarBeeHivePackageAnalysis
)
//注册命令
vscode.commands.registerCommand('BeeHive-Command.openChild', (args) => {
console.log('[BeeHive-Command.openChild] 当前选中的是:', args)
vscode.window.showInformationMessage(args)
})
vscode.commands.registerCommand(
'BeeHive-PackageAnalysis.openChild',
(args) => {
console.log('[BeeHive-PackageAnalysis.openChild] 当前选中的是:', args)
vscode.window.showInformationMessage(args)
}
)
}
然后在入口文件 extension.ts
添加该文件
import * as vscode from 'vscode'
export function activate(context: vscode.ExtensionContext) {
console.log('your extension "sugar-demo-vscode" is now active!')
require('./beehive-sidebar')(context) // demo7 自定义侧边栏入口和面板
}
export function deactivate() {}
如果需要点击左侧侧边栏的节点时触发内容,只需要在 arguments
里面回传一些内容,然后做对应的业务操作即可
效果展示
源码阅读
- beehive-sidebar.ts
- package.json 中的 viewsContainers
- package.json 中的 views
打包、发布
这东西就不需要我教了吧?搜一下还是有这方面的文章的,我就不当搬运工了,感兴趣的自行去搜一搜,或者等我后续实战文章出来看看?
唠嗑几句
上面的几个例子差不多够一个新手开发 vscode 插件了,所有的 demo 例子我都放在: learn-vscode-extension中,后面也会将实战的项目辅助工具插件放在该仓库里
如果你开发过vscode插件,你就知道文档写的有多“全”了,属于你知道很全,但是这个属性或者字段在插件中长什么样,得自己去“悟”,很蛋疼,我开发过程,如果需要些部分的插件功能,得去插件市场下载对应插件,使用一波,然后再去 github 阅读对应源码。比如我们常用的 : vscode-gitlens等
顺便澄清一下,组员不用 PC 端的项目辅助工具真的不是我写的烂!!!
贴几张图看看 PC 端的项目辅助工具,会将上边的功能都继承到该 vscode 插件中,后面 PC 端的代码 + vscode 插件代码都会脱敏开源~
- 入口

- 导入文件,历史操作区

- 导入的文件不符合规范

- 符合规范,运行命令,文章检索

太多堆积文章需要写了,等过完年再慢慢整理吧,祝大家过个好年
相关链接
- 阿宽的博客
- SugarTurboS
- vscode-gitlens
- 官方文档API
- 小茗同学-vscode插件开发全攻略
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!