拓冰建站拓冰建站
首页 / 资讯中心 / 正文

VSCode插件开发实战:用TypeScript添加侧边栏入口与Tree View面板

1. 从零拆解VSCode 侧边栏入口与 Tree View 到底怎么落地如果你正在做 VSCode 插件开发想在左侧活动栏加一个自己的图标入口点开之后出现一个可折叠、可点击、能跟命令联动的树形面板那这篇就是写给你的。核心检索词先摆出来VSCode 插件开发、侧边栏入口、Tree View、TypeScript。侧边栏入口在官方文档里叫 Tree View Container侧边栏里的面板叫 Tree View两者必须成对配置只写一个不会生效这是很多人第一次踩的坑。我试过用yo code生成 TypeScript 插件骨架然后在package.json里补viewsContainers和views再写一个TreeDataProvider把数据喂进去最后用onView:激活事件驱动加载。整套流程跑通之后F5 调试就能在活动栏看到自定义图标点开有面板区块区块里能展开根节点、子节点点击子节点还能弹消息。下面按可复制的方式把每一步拆开包括配置、代码、调试和排障。适合谁已经会写一点 TypeScript、装过 Node.js、想给团队做内部工具面板或者想给自己的插件加导航视图的开发者。不需要你精通 VSCode API但需要你能照着改文件、跑命令。2. 前置准备TaoToken 与工程骨架2.1 为什么这里会提到 TaoToken插件开发过程中经常要调模型能力比如让面板里的节点点击后去请求一段补全、生成一段说明或者做 coding agent 的交互。TaoToken 提供的是模型调用入口官网是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 。如果你只是做纯 UI 的 Tree View不接模型也能跑但如果你打算把面板做成“点击节点→请求模型→回填内容”那就需要先拿到 API Key。拿 Key 的路径进入控制台 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 在 API Keys 页面创建密钥地址是 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。如果你要验证模型是否通可以用模型对话页面 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 先试一条请求。长期做编码类插件、Agent 类插件可以看 Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。注意本篇主线是 Tree View 的 UI 与命令注册模型调用只作为“节点点击后做什么”的扩展点不把插件写成模型客户端。2.2 创建 TypeScript 插件工程用官方脚手架生成骨架语言选 TypeScriptnpm install -g yo generator-code yo code交互里选择New Extension (TypeScript)填插件名比如sidebar-demo。生成后目录大致是sidebar-demo/ package.json tsconfig.json src/ extension.ts .vscode/ launch.jsonlaunch.json里默认有Run Extension配置按 F5 会打开一个“扩展开发宿主”窗口这就是后面验证侧边栏入口的地方。3. 可复制配置package.json 里的视图容器与视图3.1 配置 viewsContainers 与 views打开package.json找到contributes补上viewsContainers和views。两者必须同时存在且views的 key 要和activitybar里的id完全一致{ contributes: { viewsContainers: { activitybar: [ { id: sidebar_test, title: 侧边栏测试, icon: media/entry.svg } ] }, views: { sidebar_test: [ { id: sidebar_test_id1, name: 面板区块名称1 }, { id: sidebar_test_id2, name: 面板区块名称2 } ] } } }几个关键点icon必须是 svg 格式放在工程里比如media/entry.svgviews的 keysidebar_test对应viewsContainers.activitybar[].id每个 view 的id是后面registerTreeDataProvider要用的字符串。配置完这一步活动栏会出现图标点开能看到两个区块标题但区块里还没有内容。3.2 注册激活事件在package.json顶层加activationEvents让视图被展开时激活插件{ activationEvents: [ onView:sidebar_test_id1 ] }如果你两个区块都要驱动可以写两条onView:。不写激活事件的话视图可能显示为空因为插件没被激活registerTreeDataProvider没执行。3.3 参数对照表配置项作用必须一致的点viewsContainers.activitybar[].id侧边栏按钮唯一标识与 views 的 key 相同viewsContainers.activitybar[].icon活动栏图标必须是 svg 路径views[containerId][].id面板区块 id与 registerTreeDataProvider 第一个参数相同views[containerId][].name面板显示名仅展示用activationEvents激活时机onView: 后接 view id4. TreeDataProvider 骨架与命令注册4.1 定义 TreeItem 与 TreeDataProvider新建src/sidebar.ts写一个最小可用的树。根节点可折叠展开后出三个子节点子节点点击触发命令import * as vscode from vscode; export class EntryItem extends vscode.TreeItem { constructor( public readonly label: string, public readonly collapsibleState: vscode.TreeItemCollapsibleState ) { super(label, collapsibleState); } } export class EntryList implements vscode.TreeDataProviderEntryItem { private _onDidChangeTreeData new vscode.EventEmitterEntryItem | undefined(); readonly onDidChangeTreeData this._onDidChangeTreeData.event; getTreeItem(element: EntryItem): vscode.TreeItem { return element; } getChildren(element?: EntryItem): vscode.ProviderResultEntryItem[] { if (element) { const children: EntryItem[] []; for (let i 0; i 3; i) { const str i.toString(); const item new EntryItem(str, vscode.TreeItemCollapsibleState.None); item.command { command: sidebar_test_id1.openChild, title: 打开子节点, arguments: [str] }; children.push(item); } return children; } return [new EntryItem(root, vscode.TreeItemCollapsibleState.Collapsed)]; } refresh(): void { this._onDidChangeTreeData.fire(undefined); } }getChildren不传参时返回根节点传参时返回该节点的子节点。item.command把点击行为和命令 id 绑定arguments会原样传给命令回调。4.2 在 extension.ts 中注册打开src/extension.ts在activate里注册 provider 和命令import * as vscode from vscode; import { EntryList } from ./sidebar; export function activate(context: vscode.ExtensionContext) { const provider new EntryList(); context.subscriptions.push( vscode.window.registerTreeDataProvider(sidebar_test_id1, provider) ); context.subscriptions.push( vscode.commands.registerCommand(sidebar_test_id1.openChild, (args: string) { vscode.window.showInformationMessage(你点击了子节点${args}); }) ); } export function deactivate() {}registerTreeDataProvider的第一个参数必须和package.json里 view 的id一致。命令 id 也要和item.command.command一致否则点击没反应。4.3 如果要做成可刷新在 provider 里加refresh()然后在命令里调用它就能在点击后更新树。比如把openChild命令改成先弹消息再刷新vscode.commands.registerCommand(sidebar_test_id1.openChild, (args: string) { vscode.window.showInformationMessage(你点击了子节点${args}); provider.refresh(); });5. 验证请求与成功结果5.1 F5 调试步骤按 F5会弹出一个新的 VSCode 窗口标题带[扩展开发宿主]。在这个窗口里看左侧活动栏应该出现你配置的 svg 图标。点击图标侧边栏展开能看到“面板区块名称1”和“面板区块名称2”。在“面板区块名称1”里应该有一个root节点点击展开箭头出现0、1、2三个子节点。点击任意子节点右下角弹出信息提示内容是你点击的编号。如果图标没出现先检查icon路径是否相对工程根目录、文件是否存在、是不是 svg。如果区块标题出现但里面空白检查activationEvents是否写了onView:sidebar_test_id1以及registerTreeDataProvider的 id 是否拼错。如果点击子节点没弹窗检查命令 id 是否两处一致。5.2 用模型对话验证扩展点如果你打算在节点点击后请求模型可以先用模型对话页面 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 发一条测试请求确认 Key 和网络通路正常。然后在命令回调里用fetch或官方 SDK 发请求把返回内容用showInformationMessage或写入某个 view 的节点。注意不要把 Key 硬编码进插件源码放到配置或环境变量里。6. 本篇常见错排查6.1 侧边栏图标不显示最常见原因是viewsContainers写了但views没写或者反过来。两者必须同时存在。第二个原因是icon不是 svg或者路径写成了绝对路径。第三个原因是package.json的 JSON 结构写错比如contributes里重复 key导致后面的覆盖前面的。6.2 面板区块出现但内容为空先看调试窗口的“扩展开发宿主”里插件是否被激活。可以在activate第一行打console.log在调试控制台看输出。如果没有输出说明激活事件没触发检查onView:后面的 id 是否和 view id 一致。如果有输出但树还是空检查getChildren是否在无参时返回了根节点数组而不是返回undefined或空数组。6.3 点击节点报“command not found”命令 id 在item.command.command和registerCommand两处必须完全一致包括大小写。另外registerCommand必须在activate里执行且插件已被激活。如果命令注册在异步回调里可能点击时还没注册完。6.4 树节点不刷新TreeDataProvider默认不会自动刷新。你需要在数据变化后触发onDidChangeTreeData。上面给的refresh()就是干这个的。如果用了EventEmitter但没在context.subscriptions里注册也可能导致事件失效。6.5 多个 view 共用同一个 provider如果你把同一个 provider 注册给两个 view id两个面板会显示同样的内容。想让它们不同就分别 new 两个 provider或者让getChildren根据 view id 分支。但registerTreeDataProvider不直接传 view id 给 provider所以更常见的做法是每个 view 一个 provider 实例。7. 继续往下走接入与长期编码Tree View 跑通之后下一步通常是把节点点击接到真实能力上。如果你要接模型先到 API Keys 页面 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 创建密钥再对照接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 把请求封装成插件里的一个服务模块。调试阶段可以用模型对话 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 快速验证参数。如果你做的是长期编码类插件或 Agent 类插件Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 里有更完整的调用方式说明。最后留一个实用技巧把package.json里的views和viewsContainers当成“注册表”把extension.ts当成“装配线”把sidebar.ts当成“数据源”。三者 id 对齐F5 就能看到结果。改完配置记得重新 F5热重载不一定能刷新视图容器。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门