1. 从零跑通第一个 VS Code Extension 到底卡在哪VS Code 插件开发这件事说难不难说简单也容易踩坑。它本质上是写一个跑在独立进程Extension Host里的 Node.js 程序通过官方 API 和编辑器主进程通信。你写的代码不会阻塞编辑器 UI这也是为什么 VS Code 装了十几个插件依然流畅的原因。插件用 TypeScript 或 JavaScript 写编译产物是一个extension.js再由package.json告诉 VS Code 什么时候加载它、加载后暴露哪些能力。适合读这篇的人有三类一是完全没写过插件、想跑通第一个 Hello World 的前端或 Node 开发者二是写过一点但被activationEvents、main字段、F5 调试窗口搞晕的人三是想把内部小工具做成团队插件、需要一份能直接复制的package.json骨架的人。我试过按官方脚手架走一遍最容易出问题的不是业务代码而是配置字段写错导致命令面板里根本搜不到你的命令。这篇会按「环境准备 → package.json 骨架 → extension.ts 最小实现 → F5 调试 → 打包验证」的顺序拆开每一步都给可复制的代码和明确的预期结果。跑完之后你会得到一个能在命令面板触发、右下角弹提示、并且能打包成.vsix的完整插件。如果你在开发过程中需要调用大模型能力做代码补全或对话后面会提到怎么用 TaoToken 的 API 接入避免自己去折腾密钥管理。2. 环境准备与 TaoToken 前置说明先确认本机有 Node.js建议 18 LTS 以上和 VS Code。命令行执行node -v和code -v能出结果就行。如果code命令不识别在 VS Code 里按CmdShiftPMac或CtrlShiftPWindows/Linux运行Shell Command: Install code command in PATH即可。脚手架工具用 Yeoman 加官方生成器打包工具用vscode/vscenpm install -g yo generator-code vscode/vsce装完后执行yo code交互式选择New Extension (TypeScript)依次填插件名、标识符、描述、是否初始化 Git。生成的项目结构里你只需要盯住两个文件package.json插件描述与扩展点和src/extension.ts入口逻辑。这里插一句关于 TaoToken 的位置。插件开发本身不需要联网但如果你打算在插件里加「选中代码让模型解释」「生成注释」这类功能就需要一个稳定的模型 API 入口。TaoToken 提供兼容 OpenAI 风格的接口官网是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 基址是 https://taotoken.net/api 。它的作用是让你在插件里用统一的 key 调用不同模型不用为每个模型单独申请账号。对插件开发者来说这意味着你可以把「模型调用」抽象成一个配置项用户填自己的 key 就能用。注意插件里调用外部 API 时密钥不要硬编码进源码应该走vscode.workspace.getConfiguration读取用户设置或者用context.secrets存储。硬编码的 key 一旦打包发布就等于泄露。3. 可复制的 package.json 骨架与字段拆解package.json是插件的身份证加说明书VS Code 靠它决定「什么时候激活你」和「你提供了什么」。下面这份骨架可以直接替换掉脚手架生成的版本字段都加了注释说明{ name: my-first-extension, displayName: My First Extension, description: 一个可运行的 VS Code 插件示例, version: 0.0.1, publisher: your-publisher-name, engines: { vscode: ^1.85.0 }, categories: [Other], activationEvents: [ onCommand:myFirstExtension.helloWorld ], main: ./out/extension.js, contributes: { commands: [ { command: myFirstExtension.helloWorld, title: Hello World, category: MyFirst } ], configuration: { title: My First Extension, properties: { myFirstExtension.apiBase: { type: string, default: https://taotoken.net/api, description: 模型 API 基址 }, myFirstExtension.apiKey: { type: string, default: , description: 模型 API Key请勿提交到版本库 } } } }, scripts: { vscode:prepublish: npm run compile, compile: tsc -p ./, watch: tsc -watch -p ./ }, devDependencies: { types/vscode: ^1.85.0, types/node: ^20.0.0, typescript: ^5.4.0 } }几个字段必须说清楚。name是插件唯一 ID发布后不能改建议用全小写加连字符。engines.vscode声明兼容的最低版本写太低可能用不了新 API写太高会挡住老用户。activationEvents决定插件何时被唤醒onCommand:xxx表示用户第一次执行这个命令时才加载这是最省资源的做法早期版本常用*表示启动即激活现在不推荐会拖慢编辑器启动。main指向编译后的 JS 文件注意是./out/extension.js而不是./src/extension.ts因为 VS Code 加载的是编译产物。contributes.commands里注册的命令 ID 必须和extension.ts里registerCommand的第一个参数完全一致大小写都不能差这是新手最常见的「命令面板搜不到」的原因。contributes.configuration是可选项但强烈建议加上。它会在 VS Code 设置界面生成可视化配置项用户不用改代码就能填 API 地址和 key。上面默认值指向 TaoToken 的 API 基址用户拿到 key 后直接填进去即可。4. extension.ts 最小实现与命令注册打开src/extension.ts替换成下面这段最小可运行代码import * as vscode from vscode; export function activate(context: vscode.ExtensionContext) { console.log(My First Extension 已激活); const disposable vscode.commands.registerCommand( myFirstExtension.helloWorld, async () { const config vscode.workspace.getConfiguration(myFirstExtension); const apiBase config.getstring(apiBase, https://taotoken.net/api); const apiKey config.getstring(apiKey, ); const editor vscode.window.activeTextEditor; const selected editor ? editor.document.getText(editor.selection) : ; if (!selected) { vscode.window.showInformationMessage(请先选中一段代码再执行命令); return; } vscode.window.showInformationMessage( 已选中 ${selected.length} 个字符API 基址${apiBase}Key 是否已配置${apiKey ? 是 : 否} ); } ); context.subscriptions.push(disposable); } export function deactivate() {}这段代码做了三件事注册命令、读取用户配置、获取当前编辑器选中内容。activate是插件被激活时的入口deactivate在插件停用时调用用来清理资源。所有需要释放的对象命令、状态栏、监听器都要push进context.subscriptions否则插件卸载时会残留。命令 IDmyFirstExtension.helloWorld和package.json里contributes.commands的command字段一一对应。vscode.window.showInformationMessage会在右下角弹出提示这是验证插件是否跑通最直观的方式。如果你想让插件真正调用模型把showInformationMessage换成fetch请求即可。TaoToken 的接口兼容 OpenAI 的/v1/chat/completions格式请求体里带上model和messages就行。密钥从配置读取不要写死。想先验证 key 是否可用可以直接在模型对话页面测试https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite 。5. F5 调试与打包验证的具体动作配置写完后按F5启动调试。VS Code 会编译 TypeScript 并打开一个新窗口标题栏带[Extension Development Host]这就是你的插件运行环境。原窗口保持不动方便你改代码后重新加载。在新窗口里按CtrlShiftPMac 是CmdShiftP打开命令面板输入Hello World应该能看到MyFirst: Hello World这一项。先随便打开一个文件选中几行代码再执行命令右下角会弹出选中字符数和配置状态的提示。如果命令面板搜不到八成是activationEvents或命令 ID 写错了回去核对package.json。调试过程中改代码在新窗口按CtrlRMacCmdR重新加载即可不用关掉重开。想看console.log输出在原窗口的「调试控制台」里查看。验证没问题后打包。在项目根目录执行vsce package会生成my-first-extension-0.0.1.vsix。安装到本地验证code --install-extension my-first-extension-0.0.1.vsix或者在 VS Code 扩展面板右上角...菜单里选Install from VSIX。安装后重启编辑器命令面板里应该能直接搜到你的命令。这一步能过说明插件的元信息、入口文件、命令注册全部正确可以进入下一步开发或发布。如果你后续要做的是长期编码类插件比如自动补全、代码审查 Agent建议了解一下 Coding Plan它更适合高频调用的场景https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 。6. 本篇常见错误排查命令面板搜不到命令。检查三处package.json的activationEvents是否包含onCommand:你的命令IDcontributes.commands里的command是否和registerCommand完全一致main是否指向编译后的./out/extension.js。改完package.json必须重启调试窗口热重载不会重新读取配置。F5 报错找不到模块 vscode。这是正常的vscode模块由编辑器运行时注入不在node_modules里。确保tsconfig.json的types包含node和vscode并且装了types/vscode。编译报错但运行正常通常就是这个类型声明的问题。打包时提示缺少 publisher 或 README。vsce package要求package.json里有publisher字段且项目根目录有README.md。publisher可以先随便填一个正式发布时才需要和 Marketplace 账号对应。另外repository字段如果填了无效地址也会报错本地打包可以先删掉。改了代码但调试窗口没变化。TypeScript 需要先编译。用npm run watch开一个监听终端或者在调试配置里加preLaunchTask自动编译。直接改.ts不编译运行的还是旧的.js。API 调用返回 401。检查配置里的 key 是否填对以及请求头是不是Authorization: Bearer key。TaoToken 的 key 在控制台创建https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 。如果插件里读取配置返回空字符串确认设置界面里填的是用户级还是工作区级配置两者作用域不同。插件激活后编辑器变卡。大概率是activationEvents用了*导致每次启动都加载。改成onCommand或onLanguage按需激活。另外activate函数里不要做同步的重计算耗时操作放异步或延迟执行。接入相关的完整字段说明和 API 用法可以对照接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。控制台里能看调用量和余额https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 。如果你用的是 Claude Code 这类工具做插件开发辅助Anthropic 兼容入口在这里https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaude_codeutm_campaignrewrite 。跑通第一个插件之后下一步通常是加菜单项、状态栏或侧边栏视图。我的建议是先把命令和配置这两块吃透因为它们是一切扩展点的地基。菜单、快捷键、视图本质上都是「把命令挂到不同位置」命令注册对了剩下的只是contributes里加字段的事。