从源码构建、调试与测试 Emmet 扩展:void 仓库内 VS Code 扩展开发实战指南

📅 发布时间:2026/9/11 4:35:51
从源码构建、调试与测试 Emmet 扩展:void 仓库内 VS Code 扩展开发实战指南
从源码构建、调试与测试 Emmet 扩展void 仓库内 VS Code 扩展开发实战指南【免费下载链接】void开源AI代码编辑器Cursor的替代方案。项目地址: https://gitcode.com/GitHub_Trending/void2/void本篇指南聚焦于当前仓库基于 VS Code 的 AI 代码编辑器 void内extensions/emmet扩展的源码开发流程覆盖两件核心事项如何从源码构建并运行该扩展打开扩展目录、按 F5 进入扩展宿主调试以及如何运行 Emmet 扩展的集成测试通过./scripts/test-integration.sh一次性执行。读完本文你将掌握该扩展在仓库中的代码组织方式、双入口激活机制、命令注册链路并具备独立搭建本地开发环境、调试运行与跑通测试的完整实战能力。1. 扩展在仓库中的定位与源码结构Emmet 扩展是随编辑器捆绑发布的官方扩展之一。根据 extensions/emmet/README.md 的说明该扩展捆绑于编辑器内可以被禁用但不能被卸载。其声明信息位于 extensions/emmet/package.json名称为emmet版本1.0.0License 为 MIT要求 VS Code 引擎版本^1.13.0及以上。从源码结构看扩展的代码主要分布在src/下三个区域src/node/Node 环境桌面端的激活入口emmetNodeMain.ts在其中额外注册了editor.emmet.action.updateImageSize命令依赖image-size库读取图片尺寸并设置用户主目录src/browser/浏览器环境Web 端的激活入口emmetBrowserMain.ts只做纯前端激活src/根目录共享逻辑emmetCommon.ts、各 Emmet 动作实现如abbreviationActions.ts、removeTag.ts、matchTag.ts、balance.ts、toggleComment.ts、evaluateMathExpression.ts、incrementDecrement.ts、reflectCssValue.ts等以及工具函数util.ts、parseDocument.ts。对应的入口声明可以在 extensions/emmet/package.json 中看到main: ./out/node/emmetNodeMain, browser: ./dist/browser/emmetBrowserMain,也就是说Node 端代码编译输出到out/而浏览器端代码经 webpack 打包输出到dist/browser/。activationEvents声明为onCommand:emmet.expandAbbreviation与onLanguage即首次触发展开命令或打开支持的语言文件时激活扩展。2. 环境准备获取源码并完成本地构建Emmet 扩展并非独立运行的程序它必须运行在完整的编辑器扩展宿主Extension Host环境中因此第一步是让整个仓库能够在本机跑起来。2.1 克隆仓库并安装依赖将仓库克隆到本地README 与 CONTRIBUTING 文档都要求先获得一个可运行的 VS Code 源码开发环境git clone https://gitcode.com/GitHub_Trending/void2/void cd void npm install仓库根目录的 package.json 与 package-lock.json 管理全部依赖npm install会一并安装所有扩展含 Emmet所需的 npm 包。2.2 认识扩展的编译任务扩展自身的scripts字段见 extensions/emmet/package.json定义了三条常用命令scripts: { watch: gulp watch-extension:emmet, compile: gulp compile-extension:emmet, deps: npm install vscode/emmet-helper }compile调用gulp compile-extension:emmet做一次性编译TS 源码 非 TS 资源拷贝到out/watch调用gulp watch-extension:emmet进入监听模式源码改动后自动重新编译配合 F5 调试非常顺手deps安装扩展核心运行时依赖vscode/emmet-helper。这些 gulp 任务在 build/gulpfile.extensions.js 中按扩展名批量生成compile-extension:emmet、watch-extension:emmet均以cleanTask清理输出目录作为前置随后通过 TypeScript 工程流水线把src下的.ts文件转译到out/并同步拷贝非 TS 资源见 build/gulpfile.extensions.js。浏览器端产物则通过扩展目录下的extension-browser.webpack.config.js配置 webpack 打包相关逻辑可在 build/gulpfile.extensions.js 的buildWebExtensions中看到。提示由于桌面端与浏览器端构建目标不同如果同时开发 Web 端能力需额外执行对应的 webpack 构建/监听任务日常只调试桌面端时gulp watch-extension:emmet即可覆盖out/产物。3. 在编辑器内打开扩展目录并按 F5 调试这是 CONTRIBUTING 文档给出的核心开发工作流共三步按官方指引准备好本地源码开发环境即第 2 节完成仓库构建在编辑器中打开extensions/emmet目录例如File Open Folder选择extensions/emmet或使用code extensions/emmet命令行打开按 F5 启动调试。3.1 F5 调试背后的原理仓库为扩展调试预置了.vscode/launch.json一类的调试配置可在仓库根目录查看F5 会启动一个开发实例主编辑器进程加载仓库源码同时以--extensionDevelopmentPath指向extensions/emmet让当前开发的扩展以源码形态被加载进扩展宿主。这样你在 Emmet 源码里设置的断点可以正常命中改动经watch-extension:emmet编译后也能在调试实例中即时反映。3.2 调试时可观察的激活入口理解激活入口有助于你下断点定位问题。桌面端入口 extensions/emmet/src/node/emmetNodeMain.ts 的activate会先注册图片尺寸更新命令再调用共享的activateEmmetExtension(context)浏览器端入口 extensions/emmet/src/browser/emmetBrowserMain.ts 则直接调用activateEmmetExtension(context)。共享激活逻辑集中在 extensions/emmet/src/emmetCommon.ts其中包括迁移并加载emmet.extensionsPath中配置的自定义 snippets/profilemigrateEmmetExtensionsPath、updateEmmetExtensionsPath注册全部editor.emmet.action.*命令如wrapWithAbbreviation、removeTag、updateTag、matchTag、balanceIn/Out、toggleComment、evaluateMathExpression、incrementNumberByOne/Ten/OneTenth及其递减版本、reflectCSSValue等每个命令都对应src/下的一个具体实现模块监听配置变更onDidChangeConfigurationemmet.includeLanguages、emmet.useInlineCompletions变化时刷新补全 Provideremmet.extensionsPath变化时重新加载扩展路径监听文档保存/打开/关闭事件保存名为snippets*.json的文件时重载 snippets对 Emmet 支持的标记语言或样式表语言维护解析缓存parseDocument.ts提供的addFileToParseCache/removeFileFromParseCache。命令清单的完整声明在 extensions/emmet/package.json所有命令都挂在commandPalette菜单下并统一使用!activeEditorIsReadonly作为显示条件只读编辑器内不展示。3.3 开发中常用的配置项速览调试开发过程中你经常需要在设置Settings里验证行为。扩展暴露的核心配置如下完整定义见 extensions/emmet/package.json中文语义说明见 extensions/emmet/package.nls.json配置项默认值说明emmet.showExpandedAbbreviationalways展开后的缩写是否以补全项形式展示可选never/always/inMarkupAndStylesheetFilesOnlyemmet.showAbbreviationSuggestionstrue是否展示可能的 Emmet 缩写建议样式表或showExpandedAbbreviationnever时不适用emmet.includeLanguages{}为默认不支持的语言映射到 Emmet 支持的语法如{vue-html: html}emmet.variables{}snippets 中使用的变量内置langen、charsetUTF-8emmet.syntaxProfiles{}指定语法对应的输出 profile 或自定义规则emmet.excludeLanguages[markdown]不展开 Emmet 缩写的语言数组emmet.extensionsPath[]自定义 syntaxProfiles / snippets 文件所在路径数组后面的路径会覆盖前面的同名配置emmet.triggerExpansionOnTabfalse按下 Tab 时即使没有补全列表也强制展开缩写emmet.useInlineCompletionsfalse使用内联补全inline completion方式给出展开建议emmet.preferences.*见 package.json细粒度行为偏好如 CSS 整数/浮点单位px/em、属性结尾符号、BEM 分隔符__/_、自闭合标签风格html/xhtml/xml、颜色短写法等emmet.showSuggestionsAsSnippetsfalse让 Emmet 建议以 snippet 形式出现便于按#editor.snippetSuggestions#排序emmet.optimizeStylesheetParsingtrue为true时只解析光标附近的 CSS/SCSS/Less 内容以判断是否可展开提升大文件性能emmet.includeLanguages与emmet.useInlineCompletions的变更会触发 extensions/emmet/src/emmetCommon.ts 中的refreshCompletionProviders它会为每个语言同时注册显式补全 Provider 与可选内联补全 Provider内联补全仅在文本与候选缩写标签完全一致时才给出建议防止输入单个字符d就弹出div/div的误扰。4. 运行 Emmet 扩展的集成测试4.1 测试形态集成测试而非单元测试CONTRIBUTING 文档明确指出Emmet 扩展的测试是以 VS Code 集成测试Integration Tests的形式运行的即测试运行在真实的扩展宿主中可以操作vscodeAPI、编辑器选区与文档模型。测试入口配置在 extensions/emmet/src/test/index.ts它引入仓库级测试运行器../../../../test/integration/electron/testrunner配置 Mochaui: tdd、超时 60 秒并根据运行环境VSCODE_BROWSER、REMOTE_VSCODE自动生成不同的测试套件名如Integration Emmet Tests、Remote Integration Emmet Tests、browser Browser Integration Emmet Tests因此同一套测试可以在桌面、Web、远程三种环境复用。4.2 运行全部集成测试含 Emmet按 CONTRIBUTING 文档的指引在仓库根目录执行./scripts/test-integration.sh该脚本位于 scripts/test-integration.sh会按顺序执行多个扩展的集成测试。通过阅读脚本可以发现它先运行 node.js 集成测试./scripts/test.sh --runGlob **/*.integrationTest.jsscripts/test-integration.sh随后逐个拉起带--extensionDevelopmentPath与--extensionTestsPath参数的开发实例运行各扩展测试其中 Emmet 部分为scripts/test-integration.shecho ### Emmet tests $INTEGRATION_TEST_ELECTRON_PATH $LINUX_EXTRA_ARGS \ $ROOT/extensions/emmet/test-workspace \ --extensionDevelopmentPath$ROOT/extensions/emmet \ --extensionTestsPath$ROOT/extensions/emmet/out/test \ $API_TESTS_EXTRA_ARGS关键参数的含义--extensionDevelopmentPath$ROOT/extensions/emmet以开发模式加载 Emmet 扩展即源码编译后的out/--extensionTestsPath$ROOT/extensions/emmet/out/test指定测试入口即上文src/test/index.ts编译产物$ROOT/extensions/emmet/test-workspace作为集成测试打开的工作区目录测试用例会在其中创建临时文件进行编辑断言$API_TESTS_EXTRA_ARGS包含--disable-telemetry、--skip-welcome、--no-cached-data、--disable-updates等隔离参数并指定崩溃报告与日志目录--crash-reporter-directory$VSCODECRASHDIR、--logsPath$VSCODELOGSDIR保证测试环境干净可复现。脚本还支持通过环境变量INTEGRATION_TEST_ELECTRON_PATH指定用已构建产物而非源码运行测试scripts/test-integration.sh这在验证发布产物时很有用。注意Emmet 测试脚本要求out/test已存在即先执行扩展编译gulp compile-extension:emmet或npm run compile再运行测试。另外 Linux 环境下脚本默认追加--disable-dev-shm-usage用于规避 Docker 容器中/dev/shm过小导致 Chromium 崩溃的问题。4.3 测试覆盖范围测试用例源码位于 extensions/emmet/src/test/与第 3 节介绍的动作模块一一对应可作为开发时理解预期行为的参考测试文件覆盖能力abbreviationAction.test.ts缩写展开动作expandAbbreviationcssAbbreviationAction.test.tsCSS 样式表中的缩写展开completion.test.ts补全 Provider 行为含includeLanguages映射场景tagActions.test.ts标签类动作移除标签、更新标签、配对标签、拆分/合并标签、合并行等wrapWithAbbreviation.test.ts用缩写包裹选区/标签editPointSelectItemBalance.test.ts编辑点跳转、条目选择、括号平衡in/outevaluateMathExpression.test.ts数学表达式求值incrementDecrement.test.ts数值增减±0.1 / ±1 / ±10reflectCssValue.test.tsCSS 值镜像reflecttoggleComment.test.ts注释切换updateImageSize.test.ts更新图片尺寸属性partialParsingStylesheet.test.ts样式表局部解析对应emmet.optimizeStylesheetParsing设置以 extensions/emmet/src/test/tagActions.test.ts 为例测试用固定 HTML 片段构造多光标选区断言updateTag、removeTag、matchTag、splitJoinTag、mergeLines等动作的输出结果测试通过testUtils.ts提供的withRandomFileEditor在随机临时文件中写入内容并执行动作最终由closeAllEditors清理编辑器。4.4 仅运行 Emmet 测试的最小方式如果不想跑完整套test-integration.sh其中还包含 TypeScript、Markdown、Git、GitHub Auth 等多个扩展的测试耗时较长可以根据上文脚本内容手工构造等价的最小命令Linux 示例./scripts/code.sh extensions/emmet/test-workspace \ --extensionDevelopmentPath$PWD/extensions/emmet \ --extensionTestsPath$PWD/extensions/emmet/out/test \ --disable-telemetry --skip-welcome --skip-release-notes \ --no-cached-data --disable-updates --use-inmemory-secretstorage \ --disable-extensions --disable-workspace-trust先确保已执行gulp compile-extension:emmet完成编译。若需复用已构建的 Electron 二进制则可像脚本那样设置INTEGRATION_TEST_ELECTRON_PATH指向构建产物路径。5. 端到端开发工作流总结综合前文一次完整的 Emmet 扩展源码开发循环如下准备环境克隆仓库 →npm install→ 首次构建含 Electron 下载可参考 scripts/test.sh 的npm i与npm run electron步骤启动监听编译进入extensions/emmet执行npm run watch等价gulp watch-extension:emmet让src/改动实时编译到out/调试运行在编辑器中打开extensions/emmet目录按 F5 启动带该扩展的调试实例在emmetCommon.ts、abbreviationActions.ts等关键模块下断点验证行为修改实现根据需求修改src/下的动作模块或调整 extensions/emmet/package.json 中的命令/配置声明注意package.nls.json中同步维护本地化描述文本回归验证在 extensions/emmet/src/test/ 中补充或修改测试用例执行./scripts/test-integration.sh或第 4.4 节的最小命令确认全部用例通过提交贡献遵循仓库根目录 CONTRIBUTING.md 与 HOW_TO_CONTRIBUTE.md 的规范提交变更。这套扩展目录内开发 F5 调试 集成测试回归的流程同样适用于仓库内其他捆绑扩展如typescript-language-features、git等它们共用 scripts/test-integration.sh 的同一测试框架掌握后即可举一反三地参与整个编辑器生态的源码开发。【免费下载链接】void开源AI代码编辑器Cursor的替代方案。项目地址: https://gitcode.com/GitHub_Trending/void2/void创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考