vscode-extension-debugger
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseVS Code Extension Debugger
VS Code扩展调试器
Overview
概述
This skill enables systematic debugging and bug fixing for VS Code extensions. It provides structured workflows for identifying root causes, analyzing error patterns, and implementing robust fixes while preventing regressions.
本Skill支持对VS Code扩展进行系统化调试与bug修复。它提供结构化流程用于定位根因、分析错误模式,并在防止回归的同时实现可靠修复。
When to Use This Skill
何时使用本Skill
- Investigating runtime errors or crashes in extensions
- Fixing memory leaks and dispose handler issues
- Resolving WebView rendering or communication failures
- Debugging extension activation or deactivation problems
- Troubleshooting message passing between Extension and WebView
- Fixing TypeScript compilation errors
- Resolving race conditions and async operation issues
- Debugging terminal-related functionality
- 排查扩展中的运行时错误或崩溃
- 修复内存泄漏与释放处理程序问题
- 解决WebView渲染或通信失败问题
- 调试扩展激活或停用故障
- 排查扩展与WebView之间的消息传递问题
- 修复TypeScript编译错误
- 解决竞态条件与异步操作问题
- 调试终端相关功能
Debugging Workflow
调试流程
Phase 1: Bug Triage and Reproduction
阶段1:Bug分类与复现
-
Gather Information
- Error messages and stack traces
- Steps to reproduce
- Environment details (VS Code version, OS, extension version)
- Frequency (always, intermittent, specific conditions)
-
Classify Bug Type
Category Symptoms Priority Crash Extension host crash, unhandled rejection P0 Memory Leak Increasing memory usage over time P0 Data Loss State not persisted, data corruption P0 Functionality Feature not working as expected P1 Performance Slow response, UI lag P1 UI/UX Visual glitches, incorrect display P2 -
Create Minimal Reproduction
- Isolate the failing scenario
- Document exact steps
- Identify triggering conditions
-
收集信息
- 错误消息与堆栈跟踪
- 复现步骤
- 环境详情(VS Code版本、操作系统、扩展版本)
- 出现频率(始终出现、间歇性出现、特定条件下出现)
-
分类Bug类型
类别 症状 优先级 崩溃 扩展宿主崩溃、未处理的拒绝 P0 内存泄漏 内存使用随时间增加 P0 数据丢失 状态未持久化、数据损坏 P0 功能问题 功能未按预期工作 P1 性能问题 响应缓慢、UI卡顿 P1 UI/UX问题 视觉故障、显示错误 P2 -
创建最小复现案例
- 隔离失败场景
- 记录精确步骤
- 确定触发条件
Phase 2: Root Cause Analysis
阶段2:根因分析
Error Analysis Strategy
错误分析策略
typescript
// Add strategic logging for investigation
console.log('[DEBUG] State before operation:', JSON.stringify(state));
try {
await problematicOperation();
} catch (error) {
console.error('[DEBUG] Error details:', {
message: error.message,
stack: error.stack,
context: currentContext
});
throw error;
}typescript
// Add strategic logging for investigation
console.log('[DEBUG] State before operation:', JSON.stringify(state));
try {
await problematicOperation();
} catch (error) {
console.error('[DEBUG] Error details:', {
message: error.message,
stack: error.stack,
context: currentContext
});
throw error;
}Common Root Cause Patterns
常见根因模式
1. Dispose Handler Issues
typescript
// Bug: Missing dispose registration
const listener = vscode.workspace.onDidChangeConfiguration(...);
// listener never disposed!
// Fix: Always register disposables
context.subscriptions.push(
vscode.workspace.onDidChangeConfiguration(...)
);2. Race Conditions
typescript
// Bug: Concurrent operations conflict
async function createTerminal() {
if (isCreating) return; // Insufficient guard
isCreating = true;
// ... creation logic
}
// Fix: Use atomic operation pattern
private creationPromise: Promise<void> | null = null;
async function createTerminal(): Promise<void> {
if (this.creationPromise) {
return this.creationPromise;
}
this.creationPromise = this.doCreateTerminal();
try {
await this.creationPromise;
} finally {
this.creationPromise = null;
}
}3. WebView Message Timing
typescript
// Bug: Message sent before WebView ready
panel.webview.postMessage({ type: 'init', data });
// Fix: Wait for ready signal
panel.webview.onDidReceiveMessage(msg => {
if (msg.type === 'ready') {
panel.webview.postMessage({ type: 'init', data });
}
});4. Null/Undefined Reference
typescript
// Bug: Assuming object exists
const terminal = this.terminals.get(id);
terminal.write(data); // Crash if undefined!
// Fix: Defensive access with early return
const terminal = this.terminals.get(id);
if (!terminal) {
console.warn(`Terminal ${id} not found`);
return;
}
terminal.write(data);5. Async/Await Errors
typescript
// Bug: Unhandled promise rejection
someAsyncFunction(); // No await, no catch!
// Fix: Proper error handling
try {
await someAsyncFunction();
} catch (error) {
vscode.window.showErrorMessage(`Operation failed: ${error.message}`);
}1. 释放处理程序问题
typescript
// Bug: Missing dispose registration
const listener = vscode.workspace.onDidChangeConfiguration(...);
// listener never disposed!
// Fix: Always register disposables
context.subscriptions.push(
vscode.workspace.onDidChangeConfiguration(...)
);2. 竞态条件问题
typescript
// Bug: Concurrent operations conflict
async function createTerminal() {
if (isCreating) return; // Insufficient guard
isCreating = true;
// ... creation logic
}
// Fix: Use atomic operation pattern
private creationPromise: Promise<void> | null = null;
async function createTerminal(): Promise<void> {
if (this.creationPromise) {
return this.creationPromise;
}
this.creationPromise = this.doCreateTerminal();
try {
await this.creationPromise;
} finally {
this.creationPromise = null;
}
}3. WebView消息时序问题
typescript
// Bug: Message sent before WebView ready
panel.webview.postMessage({ type: 'init', data });
// Fix: Wait for ready signal
panel.webview.onDidReceiveMessage(msg => {
if (msg.type === 'ready') {
panel.webview.postMessage({ type: 'init', data });
}
});4. 空值/未定义引用问题
typescript
// Bug: Assuming object exists
const terminal = this.terminals.get(id);
terminal.write(data); // Crash if undefined!
// Fix: Defensive access with early return
const terminal = this.terminals.get(id);
if (!terminal) {
console.warn(`Terminal ${id} not found`);
return;
}
terminal.write(data);5. Async/Await错误处理问题
typescript
// Bug: Unhandled promise rejection
someAsyncFunction(); // No await, no catch!
// Fix: Proper error handling
try {
await someAsyncFunction();
} catch (error) {
vscode.window.showErrorMessage(`Operation failed: ${error.message}`);
}Phase 3: Fix Implementation
阶段3:修复实现
Fix Implementation Checklist
修复实施检查清单
- Identify all affected code paths
- Consider edge cases and error scenarios
- Maintain backward compatibility
- Add defensive null checks
- Ensure proper error handling
- Register all disposables
- Add logging for debugging
- Consider performance impact
- 确定所有受影响的代码路径
- 考虑边缘情况与错误场景
- 保持向后兼容性
- 添加防御性空值检查
- 确保正确的错误处理
- 注册所有可释放资源
- 添加调试日志
- 考虑性能影响
Safe Fix Patterns
安全修复模式
Pattern 1: Guard Clause
typescript
async function processTerminal(id: number): Promise<void> {
// Early validation
if (id < 1 || id > MAX_TERMINALS) {
throw new Error(`Invalid terminal ID: ${id}`);
}
const terminal = this.getTerminal(id);
if (!terminal) {
console.warn(`Terminal ${id} not found, skipping`);
return;
}
// Safe to proceed
await terminal.process();
}Pattern 2: Try-Catch-Finally
typescript
async function safeOperation(): Promise<void> {
const resource = await acquireResource();
try {
await performOperation(resource);
} catch (error) {
await handleError(error);
throw error; // Re-throw after logging
} finally {
await releaseResource(resource); // Always cleanup
}
}Pattern 3: Timeout Protection
typescript
async function operationWithTimeout<T>(
operation: Promise<T>,
timeoutMs: number
): Promise<T> {
const timeout = new Promise<never>((_, reject) =>
setTimeout(() => reject(new Error('Operation timed out')), timeoutMs)
);
return Promise.race([operation, timeout]);
}模式1:守卫子句
typescript
async function processTerminal(id: number): Promise<void> {
// Early validation
if (id < 1 || id > MAX_TERMINALS) {
throw new Error(`Invalid terminal ID: ${id}`);
}
const terminal = this.getTerminal(id);
if (!terminal) {
console.warn(`Terminal ${id} not found, skipping`);
return;
}
// Safe to proceed
await terminal.process();
}模式2:Try-Catch-Finally
typescript
async function safeOperation(): Promise<void> {
const resource = await acquireResource();
try {
await performOperation(resource);
} catch (error) {
await handleError(error);
throw error; // Re-throw after logging
} finally {
await releaseResource(resource); // Always cleanup
}
}模式3:超时保护
typescript
async function operationWithTimeout<T>(
operation: Promise<T>,
timeoutMs: number
): Promise<T> {
const timeout = new Promise<never>((_, reject) =>
setTimeout(() => reject(new Error('Operation timed out')), timeoutMs)
);
return Promise.race([operation, timeout]);
}Phase 4: Verification
阶段4:验证
Testing Strategy
测试策略
- Unit Test the Fix
typescript
describe('Bug Fix: Terminal creation race condition', () => {
it('should handle concurrent creation requests', async () => {
const manager = new TerminalManager();
// Simulate concurrent requests
const results = await Promise.all([
manager.createTerminal(),
manager.createTerminal(),
manager.createTerminal()
]);
// Verify only expected terminals created
expect(manager.getTerminalCount()).toBe(expectedCount);
});
});-
Integration Test
- Test the actual user workflow
- Verify fix in different scenarios
- Check for regressions
-
Manual Verification
- Follow original reproduction steps
- Verify error no longer occurs
- Test related functionality
- 单元测试修复
typescript
describe('Bug Fix: Terminal creation race condition', () => {
it('should handle concurrent creation requests', async () => {
const manager = new TerminalManager();
// Simulate concurrent requests
const results = await Promise.all([
manager.createTerminal(),
manager.createTerminal(),
manager.createTerminal()
]);
// Verify only expected terminals created
expect(manager.getTerminalCount()).toBe(expectedCount);
});
});-
集成测试
- 测试实际用户流程
- 在不同场景下验证修复效果
- 检查是否存在回归
-
手动验证
- 按照原始复现步骤操作
- 验证错误不再出现
- 测试相关功能
Common Bug Categories
常见Bug类别
Memory Leaks
内存泄漏
Detection
typescript
// Add disposal tracking
class ResourceManager implements vscode.Disposable {
private disposables: vscode.Disposable[] = [];
private disposed = false;
register(disposable: vscode.Disposable): void {
if (this.disposed) {
disposable.dispose();
console.warn('Attempted to register after disposal');
return;
}
this.disposables.push(disposable);
}
dispose(): void {
if (this.disposed) return;
this.disposed = true;
// LIFO disposal order
while (this.disposables.length) {
const d = this.disposables.pop();
try {
d?.dispose();
} catch (e) {
console.error('Dispose error:', e);
}
}
}
}Common Causes
- Event listeners not removed
- Timers not cleared
- WebView panels not disposed
- File watchers not stopped
检测
typescript
// Add disposal tracking
class ResourceManager implements vscode.Disposable {
private disposables: vscode.Disposable[] = [];
private disposed = false;
register(disposable: vscode.Disposable): void {
if (this.disposed) {
disposable.dispose();
console.warn('Attempted to register after disposal');
return;
}
this.disposables.push(disposable);
}
dispose(): void {
if (this.disposed) return;
this.disposed = true;
// LIFO disposal order
while (this.disposables.length) {
const d = this.disposables.pop();
try {
d?.dispose();
} catch (e) {
console.error('Dispose error:', e);
}
}
}
}常见原因
- 事件监听器未移除
- 定时器未清除
- WebView面板未释放
- 文件监视器未停止
WebView Issues
WebView问题
Communication Failures
typescript
// Implement message queue for reliability
class MessageQueue {
private queue: Message[] = [];
private ready = false;
setReady(): void {
this.ready = true;
this.flush();
}
send(message: Message): void {
if (this.ready) {
this.webview.postMessage(message);
} else {
this.queue.push(message);
}
}
private flush(): void {
while (this.queue.length) {
this.webview.postMessage(this.queue.shift()!);
}
}
}Rendering Problems
- Check CSP (Content Security Policy)
- Verify resource URIs use webview.asWebviewUri()
- Ensure styles load correctly
- Check for JavaScript errors in WebView DevTools
通信失败
typescript
// Implement message queue for reliability
class MessageQueue {
private queue: Message[] = [];
private ready = false;
setReady(): void {
this.ready = true;
this.flush();
}
send(message: Message): void {
if (this.ready) {
this.webview.postMessage(message);
} else {
this.queue.push(message);
}
}
private flush(): void {
while (this.queue.length) {
this.webview.postMessage(this.queue.shift()!);
}
}
}渲染问题
- 检查CSP(内容安全策略)
- 验证资源URI使用webview.asWebviewUri()
- 确保样式正确加载
- 检查WebView开发者工具中的JavaScript错误
Activation Issues
激活问题
Debugging Activation
typescript
export async function activate(context: vscode.ExtensionContext) {
console.log('[Extension] Activation started');
try {
// Initialize services
await initializeServices(context);
console.log('[Extension] Services initialized');
// Register commands
registerCommands(context);
console.log('[Extension] Commands registered');
console.log('[Extension] Activation complete');
} catch (error) {
console.error('[Extension] Activation failed:', error);
vscode.window.showErrorMessage(
`Extension activation failed: ${error.message}`
);
throw error;
}
}Common Causes
- Incorrect activation events in package.json
- Exceptions during initialization
- Missing dependencies
- Circular imports
调试激活过程
typescript
export async function activate(context: vscode.ExtensionContext) {
console.log('[Extension] Activation started');
try {
// Initialize services
await initializeServices(context);
console.log('[Extension] Services initialized');
// Register commands
registerCommands(context);
console.log('[Extension] Commands registered');
console.log('[Extension] Activation complete');
} catch (error) {
console.error('[Extension] Activation failed:', error);
vscode.window.showErrorMessage(
`Extension activation failed: ${error.message}`
);
throw error;
}
}常见原因
- package.json中的激活事件配置错误
- 初始化过程中出现异常
- 缺少依赖项
- 循环导入
TypeScript Errors
TypeScript错误
Type Safety Fixes
typescript
// Bug: Implicit any and unsafe access
function processData(data) {
return data.items.map(item => item.value);
}
// Fix: Explicit types and null safety
interface DataItem {
value: string;
}
interface Data {
items?: DataItem[];
}
function processData(data: Data): string[] {
return data.items?.map(item => item.value) ?? [];
}类型安全修复
typescript
// Bug: Implicit any and unsafe access
function processData(data) {
return data.items.map(item => item.value);
}
// Fix: Explicit types and null safety
interface DataItem {
value: string;
}
interface Data {
items?: DataItem[];
}
function processData(data: Data): string[] {
return data.items?.map(item => item.value) ?? [];
}Debugging Tools
调试工具
VS Code Built-in
VS Code内置工具
-
Extension Development Host
- F5 to launch debug session
- Set breakpoints in extension code
- Inspect variables and call stack
-
Developer Tools
- Help > Toggle Developer Tools
- Console for extension host logs
- Network tab for WebView resources
-
WebView Developer Tools
- Command Palette: "Developer: Open WebView Developer Tools"
- Debug WebView JavaScript
- Inspect DOM and styles
-
扩展开发宿主
- 按F5启动调试会话
- 在扩展代码中设置断点
- 检查变量与调用栈
-
开发者工具
- 帮助 > 切换开发者工具
- 控制台查看扩展宿主日志
- 网络面板查看WebView资源
-
WebView开发者工具
- 命令面板:“开发者:打开WebView开发者工具”
- 调试WebView中的JavaScript
- 检查DOM与样式
Extension-Specific Debug Panel
扩展专用调试面板
typescript
// Terminal State Debug Panel (Ctrl+Shift+D)
// Monitors: system state, terminal info, performance metricstypescript
// Terminal State Debug Panel (Ctrl+Shift+D)
// Monitors: system state, terminal info, performance metricsLogging Best Practices
日志最佳实践
typescript
// Structured logging with context
const logger = {
debug: (component: string, message: string, data?: object) => {
if (debugEnabled) {
console.log(`[${component}] ${message}`, data ?? '');
}
},
error: (component: string, message: string, error: Error) => {
console.error(`[${component}] ${message}:`, {
message: error.message,
stack: error.stack
});
}
};typescript
// Structured logging with context
const logger = {
debug: (component: string, message: string, data?: object) => {
if (debugEnabled) {
console.log(`[${component}] ${message}`, data ?? '');
}
},
error: (component: string, message: string, error: Error) => {
console.error(`[${component}] ${message}:`, {
message: error.message,
stack: error.stack
});
}
};Prevention Strategies
预防策略
Code Review Checklist
代码审查检查清单
- All disposables registered in subscriptions
- Async operations have error handling
- Null checks for optional data
- No race conditions in concurrent operations
- WebView messages validated
- Timeouts for long-running operations
- Graceful degradation on failures
- 所有可释放资源均已注册到订阅中
- 异步操作具备错误处理
- 对可选数据进行空值检查
- 并发操作中无竞态条件
- WebView消息已验证
- 长时间操作设置超时保护
- 故障时优雅降级
Testing Requirements
测试要求
- Unit tests for fixed functionality
- Regression tests for bug scenarios
- Integration tests for affected workflows
- Memory leak tests for resource management
- 为修复的功能编写单元测试
- 为bug场景编写回归测试
- 对受影响的工作流进行集成测试
- 对资源管理进行内存泄漏测试
Resources
资源
For detailed reference documentation:
- - Catalog of common VS Code extension bugs
references/common-bugs.md - - Comprehensive debugging tool guide
references/debugging-tools.md - - Proven fix implementation patterns
references/fix-patterns.md
如需详细参考文档:
- - VS Code扩展常见bug目录
references/common-bugs.md - - 全面的调试工具指南
references/debugging-tools.md - - 经过验证的修复实现模式
references/fix-patterns.md