VSCode 扩展开发规则与最佳实践
更新时间
2025-09-27
项目结构理解
仓库关系
- 主项目:
/Users/ghost/work/WorldTourCasino/- WorldTourCasino 主仓库 - 文档子项目:
/Users/ghost/work/WorldTourCasino/docs/- 独立的 Git 仓库(不是子模块) - 扩展子项目:
/Users/ghost/work/WorldTourCasino/vscode-extensions/- 独立的 Git 仓库(不是子模块)
重要:这些是独立的 Git 仓库,通过目录挂载方式组织,不使用 Git 子模块管理。
扩展安装方式
VSCode 扩展通过符号链接方式安装,不是复制或全局安装:
bash
# 正确的安装方式
ln -sf /path/to/extension ~/.vscode/extensions/extension-name-version
# 错误的理解
❌ 扩展会被全局安装到所有项目
❌ 扩展会被复制到 extensions 目录多编辑器支持规则
支持的编辑器及目录
javascript
const SUPPORTED_EDITORS = {
'VSCode': '~/.vscode/extensions',
'Trae': '~/.trae/extensions',
'Trae-CN': '~/.trae-cn/extensions', // 注意:是 .trae-cn 不是 .traeCN
'Windsurf': '~/.windsurf/extensions',
'Cursor': '~/.cursor/extensions'
}命名规范
- 目录名称:严格按照编辑器的实际目录名,如
.trae-cn(不是.traeCN) - 扩展命名:
{name}-{version}格式,如wtc-toolbar-0.0.1
扩展激活规则
限制扩展仅在特定项目激活
1. package.json 配置
json
{
"activationEvents": [
"workspaceContains:**/WorldTourCasino.code-workspace",
"workspaceContains:.vscode/settings.json"
]
}2. 扩展代码中的检查
typescript
// 在 activate 函数中检查
export async function activate(context: vscode.ExtensionContext) {
// 检查是否是 WTC 项目
const isWTC = await checkIsWTCProject();
if (!isWTC) {
return;
}
// 检查 WTC.is_wtc 标志
const config = vscode.workspace.getConfiguration('WTC');
if (!config.get('is_wtc')) {
return;
}
// 激活扩展功能...
}工作区 vs 文件夹模式
- 工作区模式:打开
.code-workspace文件 - 文件夹模式:直接打开项目文件夹
- 重要:扩展必须在两种模式下都能正常工作
配置文件管理
隐私配置处理
敏感配置不应放在 settings.json(会被 Git 同步),应使用本地配置文件:
typescript
// 本地配置文件路径
const LOCAL_CONFIG = '.vscode/google-drive-folders.local.json';
// 自动创建配置文件
if (!fs.existsSync(localConfigPath)) {
const template = {
folders: {
"示例-文件夹": "请替换为实际的 Google Drive 文件夹 ID"
}
};
fs.writeFileSync(localConfigPath, JSON.stringify(template, null, 4));
// 自动打开配置文件让用户编辑
await vscode.window.showTextDocument(
await vscode.workspace.openTextDocument(localConfigPath)
);
}.gitignore 配置
bash
# 本地配置文件
.vscode/google-drive-folders.local.json
# 认证令牌
*/scripts/token.json
# Node modules
*/node_modules/
node_modules/
# VS Code 扩展包
*.vsixOAuth 认证自动化
自动化原则
用户要求:"请你谨记,我们要做的足够自动化"
实现方式
javascript
// 使用本地服务器自动捕获 OAuth 回调
async function getNewTokenWithDeviceCode(oAuth2Client) {
const server = http.createServer(async (req, res) => {
const reqUrl = url.parse(req.url, true);
if (reqUrl.pathname === '/' && reqUrl.query.code) {
const code = reqUrl.query.code;
// 自动交换 token
const { tokens } = await oAuth2Client.getToken(code);
// 保存 token
fs.writeFileSync(TOKEN_PATH, JSON.stringify(tokens));
// 返回成功页面
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('<h1>认证成功!</h1><p>窗口将自动关闭...</p>');
server.close();
resolve(tokens);
}
});
// 动态分配端口
const port = await getAvailablePort();
server.listen(port);
// 自动打开浏览器
const authUrl = oAuth2Client.generateAuthUrl({
redirect_uri: `http://localhost:${port}`,
access_type: 'offline',
scope: SCOPES
});
await vscode.env.openExternal(vscode.Uri.parse(authUrl));
}Git 提交规则
多仓库提交策略
- 主项目提交:需要用户明确确认
- docs 子项目:可以自动提交(用户说"提交 docs"或"都提交吧")
- vscode-extensions 子项目:独立仓库,单独提交
提交前检查
bash
# 完整的提交流程
git add -A
git commit -m "提交信息"
git pull --rebase
git push
# 如有冲突,自动 stash 并恢复
git stash
git pull --rebase
git push
git stash pop忽略构建产物
提交时忽略以下模式的文件:
res_*/flavor/index.htmlres_*/flavor/main*.cssres_*/flavor/project.jsonres_*/resource_list/**/*.jsonnode_modules/
脚本更新策略
fix-environment.sh 脚本维护
当配置结构变化时,优先考虑:
- 硬编码关键信息:避免依赖可能变化的配置结构
- 兼容性优先:使用基础 bash 语法,避免高级特性(如关联数组)
- 扩展性设计:使用数组和循环处理多个扩展和编辑器
bash
# 好的做法:硬编码扩展信息
declare -a EXTENSIONS=(
"wtc-toolbar:0.0.1:vscode-toolbar-extension"
"google-drive-uploader:0.0.1:google-drive-uploader"
)
# 避免:依赖可能变化的配置
EXTENSION_NAME=$(get_extensions_name) # 配置结构变化时会失败图标设计原则
Google Drive 上传扩展图标
用户反馈:"算了,效果不好,还是你重新找个合适的吧,要体现'上载'"
解决方案:创建云上传图标,使用 Google 品牌色彩:
- 主体:向上的箭头表示上传
- 背景:云朵形状
- 颜色:Google 四色(蓝、红、黄、绿)
调试技巧
扩展不显示的排查
- 检查符号链接是否正确创建
- 验证
activationEvents配置 - 确认
WTC.is_wtc标志设置 - 检查工作区模式 vs 文件夹模式
常用调试命令
bash
# 检查扩展链接
ls -la ~/.vscode/extensions/ | grep wtc
# 检查多个编辑器
for editor in .vscode .trae .trae-cn .windsurf .cursor; do
echo "=== $editor ==="
ls -la ~/$editor/extensions/ | grep -E "wtc|google" 2>/dev/null
done
# 调试脚本执行
bash -x script.sh 2>&1 | head -100文档记录原则
技术迭代记录位置
- 主项目技术迭代 →
docs/下的相应分类目录 - docs 子项目技术迭代 →
docs/技术文档.md - 故障排查 →
docs/故障排查/ - 工具和自动化 →
docs/工程-工具/ - VSCode 相关 →
docs/工程-工具/vscode/
文档命名规范
- 使用描述性中文名称
- 避免使用版本号或日期作为文件名
- 相关文档放在同一目录下
常见错误及解决
1. OAuth 重定向 URI 错误
错误:redirect_uri_mismatch原因:使用了废弃的 urn:ietf:wg:oauth:2.0:oob解决:使用动态 localhost 端口
2. 扩展全局可见
错误:扩展在所有项目中都显示 原因:未正确配置激活条件 解决:结合 activationEvents 和代码内检查
3. 配置读取失败
错误:extensionName 为空 原因:配置结构变更 解决:硬编码关键信息,减少配置依赖
4. Bash 兼容性问题
错误:declare -A: invalid option原因:关联数组在某些 bash 版本不支持 解决:使用普通变量和循环
终端管理最佳实践
终端复用机制
为每种任务创建专用终端,避免重复创建:
typescript
export class TerminalManager {
private terminal: vscode.Terminal | undefined;
private buildTerminal: vscode.Terminal | undefined;
private syncTerminal: vscode.Terminal | undefined;
private convertTerminal: vscode.Terminal | undefined;
async startServer(): Promise<boolean> {
// 创建或复用终端
if (!this.terminal) {
this.terminal = vscode.window.createTerminal({
name: 'WTC Docs Server',
cwd: docsPath,
iconPath: new vscode.ThemeIcon('book')
});
}
// 在同一终端执行命令
this.terminal.show(false);
this.terminal.sendText('npm run dev');
return true;
}
}reload 时清理旧终端
避免终端重复和环境贡献警告:
typescript
constructor(private configManager: ConfigManager) {
this.outputChannel = vscode.window.createOutputChannel('WTC Docs Server');
// Clean up old terminals on reload
this.cleanupOldTerminals();
// Listen for terminal close events
vscode.window.onDidCloseTerminal((closedTerminal) => {
if (closedTerminal === this.terminal) {
this.terminal = undefined;
this.isRunning = false;
}
});
}
private cleanupOldTerminals(): void {
const terminalNames = [
'WTC Docs Server',
'WTC Docs Build',
'WTC Docs Sync',
'DOCX Convert'
];
vscode.window.terminals.forEach(terminal => {
if (terminalNames.includes(terminal.name)) {
terminal.dispose();
this.outputChannel.appendLine(`Cleaned up old terminal: ${terminal.name}`);
}
});
}终端关闭监听
自动清理引用,防止内存泄漏:
typescript
vscode.window.onDidCloseTerminal((closedTerminal) => {
if (closedTerminal === this.terminal) {
this.terminal = undefined;
this.isRunning = false;
this.outputChannel.appendLine('Terminal closed');
}
});终端命名规范
使用统一的命名模式,便于识别和管理:
WTC Docs Server- 文档服务器终端WTC Docs Build- 构建任务终端WTC Docs Sync- 同步任务终端DOCX Convert- 转换任务终端
最佳实践总结
- 自动化优先:减少用户手动操作,提供一键解决方案
- 隐私保护:敏感配置使用本地文件,不提交到 Git
- 多编辑器兼容:支持主流的 VSCode 分支编辑器
- 终端管理:复用终端 + reload 自动清理,避免终端泛滥
- 错误恢复:提供清晰的错误信息和恢复方法
- 文档完善:及时记录技术决策和解决方案
- 代码简洁:移除不必要的依赖和冗余代码
- 用户友好:自动打开配置文件,提供模板和示例
功能优化记录
wtc-toolbars 扩展优化
wtc.openDocs 命令智能跳转(2025-10-16)
功能增强:
- 识别当前打开文件是否为
docs/下的 Markdown 文档 - 自动转换为对应的 VitePress URL 并打开浏览器
- 非文档文件时打开默认首页
实现逻辑:
typescript
const openDocsCommand = vscode.commands.registerCommand('wtc.openDocs', () => {
const activeEditor = vscode.window.activeTextEditor;
let targetUrl = 'https://zhaoheng666.github.io/WTC-Docs/';
if (activeEditor) {
const filePath = activeEditor.document.fileName;
const docsMatch = filePath.match(/\/docs\/(.+\.md)$/);
if (docsMatch) {
const relativePath = docsMatch[1];
const urlPath = relativePath.replace(/\.md$/, '');
targetUrl = `https://zhaoheng666.github.io/WTC-Docs/${urlPath}`;
}
}
vscode.env.openExternal(vscode.Uri.parse(targetUrl));
});使用示例:
- 打开
docs/团队.md→https://zhaoheng666.github.io/WTC-Docs/团队 - 打开
docs/工程-工具/vscode/扩展开发规则与最佳实践.md→https://zhaoheng666.github.io/WTC-Docs/工程-工具/vscode/扩展开发规则与最佳实践 - 打开其他文件 →
https://zhaoheng666.github.io/WTC-Docs/