1. 为什么我要用 VSCode 插件重写上位机工具
如果你平时用 VSCode 写代码,又经常需要调串口、看日志、发指令,那你大概率经历过这样的场景:桌面上开着串口助手、MQTT 客户端、TCP 调试工具、Markdown 编辑器,再加上 VSCode 本身,任务栏挤得连图标都看不清。我之前用 C#、Qt、Python 分别写过 HID 调试助手、串口上位机、UDP OTA 工具,每个都能跑,但集成度低,时间一长就懒得维护,最后变成一堆散落的 exe。
VSCode 插件的好处在于,它直接长在你每天用的编辑器里。你不需要切换窗口,不需要额外装运行时,插件加载完就能在命令面板里调用。华为的 LiteOS Studio、RT-Thread Studio 本质上也是走这条路,把工具链塞进 VSCode 的生态里。所以这次我打算把上位机工具逐步迁移成 VSCode 插件,而第一步就是跑通插件开发的最小闭环:环境搭建、工程创建、F5 调试、vsce 打包。
这篇文章面向的是刚接触 VSCode 插件开发、但已经会一点 TypeScript 或 Node.js 的读者。你不需要有插件开发经验,只要跟着把命令敲一遍,就能得到一个能运行、能打包的骨架工程。后面我会在这个骨架上加 TaoToken 的配置读取逻辑,让插件能对接模型对话和 API 调用,但那是下一步的事,今天先把地基打好。
2. 前置准备:Node.js、Yeoman 与 vsce 的安装
VSCode 插件本质是一个 Node.js 程序,运行在插件的宿主进程里,通过vscode模块提供的 API 和编辑器交互。所以第一件事是确认你的机器上有 Node.js 和 npm。打开终端执行:
node -v npm -v我本地是 Node 18.x,npm 9.x,这个组合没问题。如果你还没装,去 Node.js 官网下载 LTS 版本,双击安装即可,安装时记得勾选“Add to PATH”。装完后重新开一个终端,再执行上面的命令确认版本。
接下来安装两个全局工具:Yeoman 和 VSCode Extension Generator。Yeoman 是一个脚手架框架,generator-code是微软官方提供的 VSCode 插件模板生成器。一条命令搞定:
npm install -g yo generator-code如果你在国内网络环境下 npm 安装慢,可以临时切到淘宝镜像:
npm config set registry https://registry.npmmirror.com装完后验证一下:
yo --version能输出版本号就说明 Yeoman 可用了。这里顺便提一句,vsce是后面打包用的,现在先不装,等工程跑起来再装,避免一开始就堆太多工具。
3. 用 yo code 生成 TypeScript 插件骨架
在你想放工程的目录下打开终端,执行:
yo code这时候会出现一个交互式菜单,问你创建哪种类型的扩展。选项大概有这些:
- New Extension (TypeScript)
- New Extension (JavaScript)
- New Color Theme
- New Language Support
- New Code Snippets
- New Keymap
- New Extension Pack
- New Language Pack (Localization)
我们选New Extension (TypeScript)。接下来它会依次问你几个问题,我按实际输入列一下:
? What's the name of your extension? taotoken-config ? What's the identifier of your extension? taotoken-config ? What's the description of your extension? TaoToken config skeleton for VSCode ? Initialize a git repository? Yes ? Bundle the source code with webpack? No ? Which package manager to use? npm名称我用了taotoken-config,标识符保持一致。描述随便写一句能说明用途的就行。git 仓库建议选 Yes,方便后面做版本管理。webpack 选 No,因为我们现在是骨架阶段,不需要打包优化,等插件体积大了再考虑。包管理器选 npm,和前面的环境保持一致。
生成完成后,目录结构大致是这样:
taotoken-config/ ├── .vscode/ │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── .vscodeignore ├── .gitignore ├── README.md ├── package.json ├── src/ │ ├── extension.ts │ └── test/ │ ├── suite/ │ └── runTest.ts ├── tsconfig.json └── vsc-extension-quickstart.md其中最关键的两个文件是package.json和src/extension.ts。package.json里有一个contributes字段,用来声明插件向 VSCode 注册哪些能力,比如命令、菜单、配置项。extension.ts是插件的入口,activate函数在插件被激活时调用,deactivate在插件卸载时调用。
打开package.json,你会看到contributes.commands里已经注册了一个叫taotoken-config.helloWorld的命令,标题是 “Hello World”。这个就是模板自带的示例命令,我们后面会基于它改造成 TaoToken 的配置读取入口。
4. 可复制的 package.json 与 extension.ts 骨架
模板生成的代码能跑,但为了后面接入 TaoToken 的配置,我建议先把package.json和extension.ts改成更贴近实际项目的骨架。下面这份package.json你可以直接复制替换,注意name、displayName、description、publisher这几个字段按你自己的信息改。
{ "name": "taotoken-config", "displayName": "TaoToken Config", "description": "TaoToken 配置骨架,演示 VSCode 插件读取 API Key 与模型参数", "version": "0.0.1", "engines": { "vscode": "^1.85.0" }, "categories": [ "Other" ], "activationEvents": [], "main": "./out/extension.js", "contributes": { "commands": [ { "command": "taotoken-config.showConfig", "title": "TaoToken: 显示当前配置" }, { "command": "taotoken-config.setApiKey", "title": "TaoToken: 设置 API Key" } ], "configuration": { "title": "TaoToken", "properties": { "taotoken.apiKey": { "type": "string", "default": "", "description": "TaoToken API Key,用于调用模型对话与 Coding Plan" }, "taotoken.baseUrl": { "type": "string", "default": "https://taotoken.net/api", "description": "TaoToken API 基础地址" }, "taotoken.model": { "type": "string", "default": "claude-3-5-sonnet", "description": "默认使用的模型名称" } } } }, "scripts": { "vscode:prepublish": "npm run compile", "compile": "tsc -p ./", "watch": "tsc -watch -p ./", "pretest": "npm run compile && npm run lint", "lint": "eslint src --ext ts", "test": "node ./out/test/runTest.js" }, "devDependencies": { "@types/vscode": "^1.85.0", "@types/node": "18.x", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "eslint": "^8.0.0", "typescript": "^5.0.0" } }这份配置里我做了几件事:把命令从helloWorld改成showConfig和setApiKey,注册了三个配置项taotoken.apiKey、taotoken.baseUrl、taotoken.model,这样用户在 VSCode 设置里就能直接填。activationEvents留空是因为 VSCode 1.74 之后,命令注册会自动触发激活,不需要手动声明onCommand。
接着改src/extension.ts:
import * as vscode from 'vscode'; export function activate(context: vscode.ExtensionContext) { console.log('TaoToken Config 插件已激活'); const showConfig = vscode.commands.registerCommand( 'taotoken-config.showConfig', () => { const config = vscode.workspace.getConfiguration('taotoken'); const apiKey = config.get<string>('apiKey') || '(未设置)'; const baseUrl = config.get<string>('baseUrl'); const model = config.get<string>('model'); const maskedKey = apiKey.length > 8 ? apiKey.slice(0, 4) + '****' + apiKey.slice(-4) : apiKey; vscode.window.showInformationMessage( `TaoToken 配置 | BaseUrl: ${baseUrl} | Model: ${model} | Key: ${maskedKey}` ); } ); const setApiKey = vscode.commands.registerCommand( 'taotoken-config.setApiKey', async () => { const input = await vscode.window.showInputBox({ prompt: '请输入 TaoToken API Key', password: true, placeHolder: 'sk-...' }); if (input === undefined) { return; } await vscode.workspace .getConfiguration('taotoken') .update('apiKey', input, vscode.ConfigurationTarget.Global); vscode.window.showInformationMessage('TaoToken API Key 已保存'); } ); context.subscriptions.push(showConfig, setApiKey); } export function deactivate() {}这段代码做了两件事:showConfig读取当前配置并弹窗显示,API Key 做了脱敏处理,只显示前四位和后四位;setApiKey弹出一个密码输入框,用户输入后写入全局配置。context.subscriptions.push把两个命令的 Disposable 注册进去,插件卸载时会自动清理。
5. F5 调试与 vsce 打包验证
代码改完后,先编译一遍确认没有类型错误:
npm run compile如果终端没有报错,说明 TypeScript 编译通过。接下来按 F5 启动调试。VSCode 会读取.vscode/launch.json里的配置,打开一个新的“扩展开发宿主”窗口。这个新窗口里,你刚才写的插件已经加载了。
在新窗口里按Ctrl+Shift+P打开命令面板,输入TaoToken,应该能看到两个命令:
- TaoToken: 显示当前配置
- TaoToken: 设置 API Key
先执行“设置 API Key”,随便输入一个测试值,比如sk-test-1234567890。然后再执行“显示当前配置”,右下角会弹出通知,显示 BaseUrl、Model 和脱敏后的 Key。如果能看到这个通知,说明插件的配置读写链路已经跑通了。
调试没问题后,开始打包。先全局安装 vsce:
npm install -g vsce打包前有两个坑必须处理。第一,package.json里必须有publisher字段,否则 vsce 会报错。在package.json顶层加一行:
"publisher": "your-name",your-name换成你自己的标识,后面如果真要发布到市场,这个标识要和你的 publisher 账号一致。第二,README.md不能是模板默认内容,vsce 会检查并报错。把README.md改成你自己的说明,哪怕只写一句“TaoToken Config 插件骨架”也行。
处理完这两个地方,执行打包:
vsce package终端会输出类似这样的信息:
DONE Packaged: /path/to/taotoken-config-0.0.1.vsix (12 files, 8.5KB)生成的.vsix文件就是插件包。你可以在 VSCode 里通过“扩展”面板右上角的...菜单选择“从 VSIX 安装”,选中这个文件,安装后重启窗口,插件就能用了。也可以把这个文件发给别人,对方同样方式安装。
6. 本篇常见错误排查
第一个常见错误是npm run compile报Cannot find module 'vscode'。这是因为@types/vscode没装好,或者tsconfig.json里的types配置有问题。检查node_modules/@types/vscode是否存在,如果没有,执行npm install重新拉依赖。
第二个错误是 F5 之后新窗口里命令面板搜不到命令。先确认package.json的contributes.commands里命令 ID 和extension.ts里registerCommand的 ID 完全一致,大小写都不能差。再确认activationEvents是否为空数组,VSCode 1.74 以上版本命令注册会自动激活,但如果你的 VSCode 版本较老,需要手动加onCommand:taotoken-config.showConfig。
第三个错误是vsce package报ERROR Missing publisher name。这就是前面说的publisher字段没加。加上后重新执行即可。
第四个错误是vsce package报ERROR README.md not found or empty。检查README.md是否存在且内容不为空。模板生成的 README 有时候会被清空,补上内容就行。
第五个错误是打包时提示This extension consists of X files. For performance reasons, you should bundle your extension。这是警告不是错误,可以忽略。如果想去掉,可以在package.json里加"files"字段白名单,或者后面引入 webpack 打包。
7. 下一步:把配置骨架接到 TaoToken
到这里,一个能调试、能打包的 VSCode 插件骨架就完成了。你现在有了命令注册、配置读取、输入框交互、全局配置写入这几个基础能力,后面加功能就是往extension.ts里继续注册命令。
下一步我打算在这个骨架上接入 TaoToken 的 API 调用。具体来说,用taotoken.apiKey和taotoken.baseUrl构造请求,调用模型对话接口,把返回结果展示在 VSCode 的输出面板或者 Webview 里。如果你要长期做编码类插件,建议直接看 Coding Plan 的接入方式,它更适合 Agent 场景;如果只是先验证模型能不能通,可以先在模型对话页面拿一个 Key 试一次请求。
接入文档里有完整的请求示例和参数说明,API Key 在控制台的 API Keys 页面生成。我建议你先把今天这个骨架跑通,确认 F5 调试和 vsce 打包都没问题,再去接真实请求。因为插件开发最容易卡住的地方不是业务逻辑,而是环境、编译、打包这些工程环节。骨架稳了,后面加什么功能都快。