外观
VSIX 插件开发
VSIX 是 VS Code 扩展的安装包格式。扩展通过 package.json 声明身份、宿主兼容范围、运行入口以及命令和设置等贡献点,实际功能由扩展宿主中的代码实现。兼容编辑器还需确认其支持的 VS Code API 版本。
插件配置
示例清单
以下示例使用虚构的笔记插件,名称、发布者、版本、路径和服务地址均为示例值,枚举与字段类型保留合法写法。这里只展示影响最终插件身份、展示、属性和运行行为的配置,不涉及工程任务。入口和资源文件需由实际工程提供。
基础清单对应原配置已有字段;后续标注“可选扩展”的配置用于补充图标、菜单、快捷键、侧栏等能力,并非原插件已经实现的功能。
json
{
"name": "sample-notes",
"displayName": "示例笔记",
"description": "在编辑器标签页中查看和编辑示例笔记。",
"version": "0.2.0",
"publisher": "sample-studio",
"license": "MIT",
"engines": {
"vscode": "^1.96.0"
},
"categories": ["Productivity"],
"activationEvents": ["onWebviewPanel:sampleNotes.panel"],
"main": "./lib/host.cjs",
"contributes": {
"commands": [
{
"command": "sampleNotes.open",
"title": "示例笔记:打开面板"
}
],
"configuration": {
"title": "示例笔记",
"properties": {
"sampleNotes.endpoint": {
"type": "string",
"default": "https://notes.example.com",
"scope": "machine",
"description": "笔记服务的 HTTPS 源地址,不包含业务路径。"
}
}
}
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
展示与身份
name:扩展的机器名称,用于标识和打包,不是用户看到的标题。通常使用小写字母和连字符。displayName:扩展列表和详情页显示的名称,可使用中文。description:扩展简介,说明用途,不负责定义功能入口。version:遵循语义化版本格式,用于识别安装包版本和更新。发布新包时应按变更性质递增。publisher:发布者标识。与name组合形成扩展 ID,例如sample-studio.sample-notes;发布到市场时需使用实际发布者账号。license:授权声明。示例MIT表示采用 MIT 许可证,应配套许可证正文;UNLICENSED表示不授予开源许可,不等于没有填写该字段。categories:扩展市场的分类数组,如Productivity、Other。必须使用受支持的分类,不会因此生成活动栏入口。
可选扩展: 以下字段影响扩展详情和资源展示,可补充到清单顶层。
json
{
"icon": "assets/extension-logo.png",
"homepage": "https://notes.example.com/help",
"repository": {
"type": "git",
"url": "https://github.com/sample-studio/sample-notes"
}
}1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
icon:扩展列表和详情使用的图标路径,相对于扩展根目录;图片需包含在安装包中。它不是活动栏图标。homepage:项目主页或使用说明链接。repository:源码仓库类型与地址,供详情页和市场展示仓库信息,不影响宿主执行逻辑。
宿主兼容性与激活
engines.vscode:扩展要求的 VS Code 版本范围。示例^1.96.0表示不低于1.96.0且低于2.0.0;这不是 Node.js 版本要求,也不能保证所有兼容编辑器都支持所用 API。activationEvents:触发扩展激活的事件列表。激活时宿主加载扩展入口并调用导出的activate()。onWebviewPanel:sampleNotes.panel:恢复指定类型的 Webview 面板时激活扩展。后缀是面板类型,不是命令 ID,需与创建面板和注册序列化器使用的类型一致。
恢复面板不等于首次打开面板。 onWebviewPanel 配合 registerWebviewPanelSerializer() 恢复已有标签页;首次打开通常由用户执行命令触发。
VS Code 自 1.74 起,对 contributes.commands 中声明的命令自动生成相应激活行为,不必再重复声明 onCommand。针对更旧宿主时需显式配置相应激活事件,并核对 API 兼容范围。
扩展运行入口
main 指向扩展宿主加载的 JavaScript 文件,路径相对于扩展根目录。示例 ./lib/host.cjs 是构建后的 CommonJS 入口,不应指向未经处理的 TypeScript 源码或 Webview 的 HTML 页面。
入口模块通常导出:
activate(context):注册命令、面板恢复逻辑和事件监听器。deactivate():按需释放资源。
命令和事件注册返回的可释放对象通常加入 context.subscriptions,由宿主在扩展停用时清理。
扩展宿主与 Webview 是两个运行环境。 宿主调用 vscode API,Webview 渲染前端页面;二者的构建产物都需要包含在安装包中。
交互入口
contributes.commands 声明编辑器可发现的命令:
command:唯一命令 ID,例如sampleNotes.open,必须与宿主代码registerCommand()的 ID 一致。title:命令面板显示的名称,例如“示例笔记:打开面板”。category(可选扩展):命令的显示分组;使用它时可将title简化为动作名称。icon(可选扩展):命令显示为工具栏按钮时使用的图标,例如$(notebook),也可配置图标资源路径。enablement(可选扩展):控制命令可执行状态的上下文表达式,不等同于菜单是否可见。
声明命令只提供可发现的入口,不会实现命令处理逻辑,也不会自动生成左侧栏图标或按钮。用户执行命令后,宿主才按实现打开面板等界面;安装完成不代表页面会自动打开。
可选扩展: 以下片段合并到基础清单的 contributes 对象中,为同一命令增加菜单和快捷键,并声明侧栏 Webview 视图。
json
{
"menus": {
"view/title": [
{
"command": "sampleNotes.open",
"when": "view == sampleNotes.sidebar",
"group": "navigation"
}
]
},
"keybindings": [
{
"command": "sampleNotes.open",
"key": "ctrl+alt+n",
"mac": "cmd+alt+n",
"when": "editorTextFocus"
}
],
"viewsContainers": {
"activitybar": [
{
"id": "sample-notes",
"title": "示例笔记",
"icon": "assets/activity-notes.svg"
}
]
},
"views": {
"sample-notes": [
{
"id": "sampleNotes.sidebar",
"name": "笔记列表",
"icon": "assets/activity-notes.svg",
"type": "webview"
}
]
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
menus:键名指定菜单位置,示例view/title表示视图标题栏;command引用已声明命令,when控制显示条件,group控制分组和位置。navigation通常用于标题栏主操作。keybindings:为已有命令绑定按键;key是默认组合,mac覆盖 macOS 组合,when限制触发上下文。示例只在编辑器文本获得焦点时生效,仍可能被用户配置覆盖或与其他快捷键冲突。viewsContainers.activitybar:声明活动栏容器;id是容器标识,title是名称,icon是活动栏图标资源路径,与顶层扩展icon分工不同。views:以容器 ID 为键声明视图;id标识视图,name是视图标题,type: "webview"表示由 Webview 视图提供内容。不指定该类型时,通常按树视图实现。
容器 ID 仅使用字母、数字、下划线或连字符,不使用点号,并且必须与 views 的键一致;视图 ID 可使用点号,菜单条件里的视图 ID 必须与 views[].id 一致。Webview 视图需要宿主通过 registerWebviewViewProvider() 注册相同视图 ID 的内容提供器;树视图则需对应的数据提供器。
侧栏视图与编辑器 Webview 标签页不是同一对象。 示例侧栏 ID sampleNotes.sidebar 不应混用为恢复标签页的类型 sampleNotes.panel。现代 VS Code 可根据声明的视图自动激活扩展,但视图内容仍由运行代码实现。
侧栏按钮入口
如果只希望从侧栏召唤现有编辑器标签页,无需把整个应用迁移为侧栏 Webview。可复用前面的活动栏容器,将其 views 替换为树视图,并增加 viewsWelcome:
json
{
"views": {
"sample-notes": [
{
"id": "sampleNotes.launcher",
"name": "示例笔记",
"icon": "assets/activity-notes.svg"
}
]
},
"viewsWelcome": [
{
"view": "sampleNotes.launcher",
"contents": "在编辑器标签页中管理笔记。\n[打开笔记](command:sampleNotes.open)"
}
]
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
viewsWelcome.view:关联目标视图 ID,此处是sampleNotes.launcher。contents:欢迎内容,支持命令链接;独占一行的命令链接显示为按钮,点击执行已声明并注册的sampleNotes.open。- 宿主通过
registerTreeDataProvider()注册同名树视图;入口方案的getChildren()返回空数组,getTreeItem()返回传入项。欢迎内容在树为空且没有视图消息时显示,不设置TreeView.message。 - 数据提供器注册返回的可释放对象加入
context.subscriptions。仅声明视图而未注册提供器,不能视为入口实现完成。 - 该示例替换了侧栏视图 ID,若保留前面的标题栏菜单,需同步修改
when条件。编辑器面板类型sampleNotes.panel不变。
点击活动栏图标只展开侧栏,点击欢迎按钮才打开标签页。重复打开时是否切回已有标签页而非创建多个面板,取决于现有打开命令的单例实现,不由这些配置自动保证。
活动栏建议使用透明背景的单色 SVG,例如 24 × 24 的笔记本轮廓,并验证浅色、深色主题下的辨识度。顶层扩展图标与活动栏图标用途不同,应分别配置;视图的 icon 用于需要视图图标的展示位置,例如视图被移动后的活动栏入口。
设置属性
contributes.configuration 定义编辑器设置中的扩展配置:
title:设置分组名称。properties:以设置键为索引的配置项集合。建议带扩展前缀,避免与其他扩展冲突。properties[设置键].type:值类型,示例string表示字符串。properties[设置键].default:用户未配置时的默认值,不应写入密钥或个人凭据。properties[设置键].scope:设置的适用范围。示例machine表示机器级设置,不允许工作区或文件夹覆盖,通常也不参与设置同步;若需要工作区覆盖,应评估machine-overridable等合法范围。properties[设置键].description:设置界面的帮助文字。描述约束不会自动实现业务校验,宿主仍需验证地址格式等条件。
对于 sampleNotes.endpoint,宿主可通过 workspace.getConfiguration("sampleNotes").get<string>("endpoint") 读取;服务地址变化时是否关闭面板、隔离会话等,需要扩展自行实现。
可选扩展: 可在 properties 中增加限制可选值、调整界面顺序的配置。
json
{
"sampleNotes.layout": {
"type": "string",
"default": "compact",
"enum": ["compact", "comfortable"],
"enumDescriptions": ["紧凑排列笔记。", "增大笔记间距。"],
"scope": "window",
"description": "笔记列表的显示密度。",
"order": 20
}
}1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
enum:限制可选值,字符串枚举通常在设置界面显示为下拉选项;default应是其中的合法值。enumDescriptions:按枚举顺序提供选项说明。order:影响设置项的显示顺序,不改变设置值的优先级。scope: "window":窗口级配置,允许用户和工作区设置,不按单个资源独立取值;适用于整个编辑器窗口内统一生效的选项。minimum、maximum:数值类型的范围约束。pattern:字符串的正则约束,例如约束地址前缀;它不能替代完整 URL 校验或网络连接验证。markdownDescription:支持 Markdown 的设置说明,用于链接和强调等展示。
类型与约束用于设置界面的提示和配置校验,不会自动改变业务页面。示例显示密度需要宿主或 Webview 读取配置并应用;来自配置之外的输入也需自行验证。
安装包内容
可选扩展: 文件筛选会直接影响安装包中可加载的入口、图标、Webview 资源和运行时依赖。
files:package.json顶层的文件包含列表,用于声明要包含的目录或文件。.vscodeignore:扩展根目录的独立排除文件,用于过滤不应进入安装包的内容,不是清单字段。
不同打包工具版本对两种筛选方式的支持和组合限制可能不同,应按工具约定选用,不能简单当作互相叠加的两层过滤。
文件筛选必须与 main、顶层 icon、活动栏图标及 Webview 引用路径对应。配置声明了资源路径并不意味着文件会自动存在;误排除入口会导致激活失败,误排除图片或页面资源会导致图标缺失或页面加载异常。
对于单独新增的活动栏图标,应明确将 assets/activity-notes.svg 纳入安装包;若采用默认排除全部文件的 .vscodeignore,需精确放行该路径,不必放开整个资源目录。核验安装包时同时检查清单引用、图标是否存在及是否与当前源文件一致;仅检查页面资源引用无法覆盖清单中的图标路径。
版本更新与入口可见性
version 用于识别更新,不是开启活动栏的开关。新增侧栏配置后,建议递增版本号,例如从 0.2.0 改为 0.2.1,让新旧安装包可区分;这不代表只有升级版本号才能显示侧栏。
- 保持
publisher和name不变,才能作为同一扩展更新;修改它们会改变扩展 ID,可能形成两个并存的插件。 - 同版本覆盖安装的行为需以宿主实际支持为准,不能仅凭安装成功提示确认新清单已加载。通常不需要先卸载旧插件,但安装后应确认实际版本并按宿主提示重载窗口。
- 入口布局可能被用户隐藏、折叠或移动;配置声明活动栏容器,并不保证它始终出现在左侧固定位置。
安装后仍不显示入口时,按以下顺序核对:
- 安装身份与版本:确认目标编辑器中插件已启用、实际版本正确,且安装的是包含新配置的包,而非同名旧包。
- 实际加载的清单:检查安装目录中的
package.json是否包含viewsContainers、views,容器 ID 是否合法且与视图容器键一致。 - 资源与布局:检查包内图标路径,查看活动栏的“更多”、右键菜单和其他侧栏位置,排除隐藏或移动的视图。
- 注册与日志:若图标出现但视图报错或按钮不显示,检查提供器注册 ID、树是否为空、视图消息及扩展宿主日志;按钮不可用时检查命令声明、注册与可执行条件。
- 旧安装残留:确认新版本仍未生效时,再尝试卸载旧插件、重载窗口、安装新包并再次重载。重装是排除残留的手段,不是侧栏配置的必需步骤,也不保证清除用户保存的视图布局。
- 兼容宿主支持:核对该编辑器对活动栏贡献点、视图 API 和窗口重载的支持;必要时在满足
engines.vscode的 VS Code 中对照验证。
源码配置正确或安装包校验通过,不等于目标编辑器已经加载新包,也不等于兼容宿主完整支持这些入口。宿主文档未说明的行为应保留为待验证项,不能断定入口缺失一定由版本号造成。