vscode插件核心是activate和deactivate函数的正确使用:activate仅执行一次,须注册命令、监听器并push至context.subscriptions以防内存泄漏;deactivate必须返回promise以确保异步清理完成,且activationevents与contributes严格匹配否则插件静默失效。

VSCode 插件本身没有“函数生命周期”这个概念——你真正要管理的,是 activate 和 deactivate 这两个由 VSCode 主进程调用的入口函数,以及它们内部所创建资源的存活周期。搞错这点,就容易把插件写成内存泄漏、命令失效或重启后状态丢失的“半残品”。
为什么 activate 只执行一次,但你的逻辑却没持续生效?
VSCode 调用 activate 后不会反复触发,它只是启动入口;后续所有行为(比如监听文件保存、响应命令、更新视图)都得靠你在 activate 里手动注册并长期持有引用。一旦引用丢失,监听就断了。
-
vscode.workspace.onDidSaveTextDocument返回的是Disposable,必须传给context.subscriptions.push(),否则窗口重载后监听自动注销 - 直接写
onDidSaveTextDocument(() => { ... })而不存引用,等于每次保存都新建一个监听器,旧的没释放 → 内存泄漏 + 多次触发 - 如果你在
activate里 new 了一个类实例(比如new ComplexityAnalyzer()),但没把它存在context或模块级变量里,下次命令调用时可能拿到新实例,缓存/状态全丢
deactivate 不是可选的,它是资源清理的唯一可靠时机
VSCode 在关闭窗口或禁用插件前会调用 deactivate,但它**不会等异步操作完成**——除非你显式返回 Promise。很多插件在这里漏掉清理,导致后台任务继续跑、WebSocket 未关闭、定时器还在 tick。
- 清除所有
setInterval/setTimeout,记下 ID 并在deactivate中clearInterval(id) - 关闭
vscode.window.createWebviewPanel创建的面板:调用panel.dispose() - 如果用了
outputChannel,记得channel.dispose(),否则日志通道残留 - 返回 Promise:例如
return myServer.shutdown(),VSCode 会等 resolve 后再卸载插件
activationEvents 配错,activate 根本不会被调用
package.json 里 "activationEvents" 写错,VSCode 就当插件不存在——控制台没报错、断点不命中、console.log 也不输出,纯静默失败。
- 命令型激活必须匹配:如果注册了
vscode.commands.registerCommand('my.ext.do', ...),activationEvents就得有"onCommand:my.ext.do" -
"onLanguage:javascript"不等于"onLanguage:js"—— 语言 ID 以 VSCode 官方定义为准(查vscode.languages.getLanguages()) -
"*"确实一启动就激活,但会拖慢 VSCode 启动速度,尤其插件做了 heavy 初始化(如加载 AST 解析器) - 漏写
"main": "./extension.js"或路径错误,activate函数压根找不到,连入口都进不去
调试时断点失效,大概率是 launch.json 或 sourceMap 没对上
VSCode 插件运行在 Extension Host 进程,不是主窗口进程。直接 F5 启动主窗口,activate 永远不会执行。
-
launch.json的type必须是"extensionHost",不能是"pwa-node"或"pwa-chrome" -
outFiles要精确指向编译后的 JS 路径,比如["${workspaceFolder}/out/**/*.js"],且tsconfig.json中sourceMap: true和outDir: "./out"必须一致 - 改完 TypeScript 代码后,必须手动
Cmd+R/Ctrl+R重载窗口,TS 编译不会自动触发热更新 -
console.log输出在 “Developer Tools → Console”,不是 “Output” 面板;想在 Output 面板显示,要用context.extensionPath+vscode.window.createOutputChannel
最关键的细节往往藏在 package.json 的 activationEvents 和 context.subscriptions 的配对关系里——少 push 一个 Disposable,多写一个 * 激活,或者忘了 return Promise,都会让插件看起来“有时工作、有时失灵”。这不是玄学,是 VSCode 运行模型的硬约束。











