Angular monorepo 中 VSCode Angular Language Service 扩展的本地开发指南:依赖管理、VSIX 构建与调试
【免费下载链接】angularDeliver web apps with confidence 🚀项目地址: https://gitcode.com/GitHub_Trending/an/angular
本篇技术指南面向希望在 Angular 主仓库(angular/angular)中为 VSCode Angular Language Service(ng-template)扩展贡献代码的开发者,完整讲解其 monorepo 组织方式、bazel-bin产物目录与依赖同步规则、通过pnpm --filter=ng-template run package构建.vsix安装包,以及在 VSCode Extension Development Host 中一键编译、启动扩展开发实例并挂接语言服务器调试器的完整工作流。读完本文,你将掌握从克隆仓库到「修改代码 → 自动编译 → 打开开发实例 → 附加调试器」的闭环开发方法。
一、模块定位:vscode-ng-language-service 在 Angular monorepo 中的角色
Angular 主仓库是一个巨型 monorepo,而vscode-ng-language-service是其中负责「编辑器体验」的独立子项目,对应 VSCode 扩展ng-template(displayName 为 Angular Language Service)。它并不直接包含 Angular 编译器的模板解析逻辑,而是将 @angular/language-service 与 TypeScript 编译器作为后端依赖,通过语言服务器协议(LSP)为 VSCode 提供 Angular 模板的补全、诊断、跳转定义、文档符号(Document Symbols)与 Inlay Hints 等能力。其 LSP 服务器实现见 server/README.md 中描述的@angular/language-server包。
从目录结构看,该模块由以下部分组成:
- client:VSCode 扩展客户端,负责激活扩展、管理语言客户端生命周期与命令注册;
- server:基于
vscode-languageserver的 LSP 服务器,实际承载语言能力; - common:客户端与服务器共享的自定义 LSP 通知/请求定义(如
IsInAngularProject、GetTcbRequest等); - syntaxes:TextMate 语法高亮定义(inline-template、template-blocks、let-declaration 等);
- integration:集成测试与 e2e 测试工程。
在开发该模块时,需要理解一个核心前提:这个 monorepo 的构建产物统一输出到bazel-bin目录。这意味着客户端与服务器源码通过 Bazel 编译后,产物都落在bazel-bin下,无论是打包.vsix还是调试加载,都需要依赖这条产物链路。
二、Monorepo 构建设置与依赖同步规则
根据 DEVELOPER.md 的说明,本项目是一个 monorepo,所有构建输出都产生在bazel-bin目录中。例如客户端入口 package.json 中main字段指向../dist/bin/vscode-ng-language-service/client/src/extension.js,即 Bazel 输出目录下的编译产物;client.ts 在启动服务器时也同时探测生产包server与开发产物bazel-bin/server/src/server.js。
2.1 根 package.json 必须覆盖全部生产依赖
开发文档强调:根目录 package.json 的dependencies必须包含客户端和服务器双方的全部生产依赖。这是因为 monorepo 采用单一锁文件(pnpm-lock.yaml)统一安装依赖,任何一层缺漏都会导致构建或运行期解析失败。
2.2 server 依赖需要在两处重复声明
其中特别需要注意的是:server 的依赖必须在根 package.json 中重复一份。因此,每当为服务器新增一个生产依赖时,需要同时把它添加到:
- 根 package.json;
- server/package.json。
查看当前 server/package.json,其生产依赖为@angular/language-service: workspace:*与typescript: 6.0.3,这两个包同样出现在根 package.json 与扩展 package.json 的dependencies中,正是这一同步规则的落地体现。workspace:*表明使用工作区内源码版本的 language-service,这也是扩展始终内置最新版 language-service 的原因。
此外,BUILD.bazel 中vsix_sandbox目标也手动列出了打包所需的传递依赖:node_modules/@angular/language-service与:node_modules/typescript,注释说明了这是为了避免vsce打包时额外执行一次npm install。
三、构建扩展 .vsix 安装包
3.1 执行打包命令
如需构建扩展的.vsix安装包,在仓库根目录执行:
pnpm --filter=ng-template run package该命令实际执行的是 package.json 中的package脚本:
"package": "bazel build //vscode-ng-language-service:development_package --config=release"即通过 Bazel 构建development_package目标(使用 release 配置)。
3.2 产物位置
构建完成后,.vsix文件位于:
./dist/bin/vscode-ng-language-service/ng-template.vsix这个路径与 BUILD.bazel 中vsce规则(vsix目标)的产出ng-template.vsix一致,也对应发布脚本 tools/release.mts 中extensionPath的取值。
3.3 打包流水线拆解
从 BUILD.bazel 可以还原完整的打包链路:
expand_template_rule生成package_expanded.json:将workspace:*替换为实际版本号(stamp 场景下用{{STABLE_PROJECT_VERSION}},否则用0.0.0),并把main路径改写为./index;npm_package组装vsix_sandbox:汇集 CHANGELOG、README、icon、schema、client/server/syntaxes 编译产物及 language-service、typescript 两个 npm 包;vsce_bin.vsce调用vsce package在vsix_sandbox目录内生成ng-template.vsix(注意 args 中的--allow-package-env-file、--allow-package-all-secrets标志);development_package将vsix与其 sandbox 一起打包,供开发调试与 e2e 测试引用;vsix_contents_golden_file生成并校验 vsix 内容清单,对照文件为 goldens/vscode-extension/vsix_package_contents.txt。
3.4 版本发布流程
若需走完整发布流程(版本号提升、changelog 生成、构建、打 tag、上传 release),可运行扩展 package.json 中的release脚本:node tools/release.mts。其实现位于 tools/release.mts,流程包括:校验工作区干净、读取当前版本并提示输入新版本(默认建议 patch)、创建vscode-release-<version>分支、生成 changelog、执行pnpm --filter=ng-template run package构建扩展、创建并推送vsix-<version>标签,最后上传产物到 GitHub Release 并用vsce publish发布。注意该脚本依赖GITHUB_TOKEN环境变量,且发布前会提示人工先在开发实例中验证产物。
四、在 VSCode 中测试本地修改(Extension Development Host)
对仓库中代码的任何修改,都需要在一个开发版 VSCode(Extension Development Host,扩展开发宿主窗口)中实际验证。.vscode目录下的脚本已经配置好「自动编译代码 → 启动带 Angular 扩展的新 VSCode 实例」的完整链路。
4.1 启动扩展开发客户端
有两种方式启动:
- 在 VSCode 中直接按F5;
- 打开左侧 Run(运行)面板,从任务列表中选择
VSCE: Launch Dev Client。
VSCE: Launch Dev Client对应 launch.json 中的extensionHost类型配置,其关键参数为:
runtimeExecutable: ${execPath}—— 使用当前 VSCode 可执行文件作为宿主;args: --extensionDevelopmentPath=${workspaceFolder}/vscode-ng-language-service—— 以源码目录作为扩展开发路径加载;preLaunchTask: VSCE: watch bundles—— 启动前先运行 watch 任务。
preLaunchTask引用的VSCE: watch bundles定义在 tasks.json 中,它执行:
pnpm --filter=ng-template run watch即ibazel build //vscode-ng-language-service/client/src //vscode-ng-language-service/server/src(见 package.json),以增量 watch 模式持续编译客户端与服务器源码,并配置了beginsPattern/endsPattern两个背景任务匹配模式,用于识别 ibazel 启动与构建完成的状态。
4.2 附加调试器到语言服务器
客户端启动后,可以可选地将调试器附加到语言服务器进程:
- 打开左侧 Run(运行)面板,从任务列表中选择
VSCE: Attach to Server。
该配置(见 launch.json)是node类型的 attach 请求,监听6009端口,并开启了 source maps 与sourceMapPathOverrides映射(将?*/bin/*映射回工作区源码目录),从而可以直接在server源码上打断点调试。
为什么端口是 6009?因为客户端在启动语言服务器时(见 client.ts),debug 模式下会为 Node 进程追加--inspect-brk=6009,并设置NG_DEBUG=true环境变量,代码注释明确提示「如果修改调试端口,请同步更新 .vscode/launch.json」。
4.3 一步到位:客户端 + 调试器
作为快捷方式,仓库还提供了一个组合任务,可以一步完成「启动开发客户端并附加调试器」:
- 打开左侧 Run(运行)面板,选择
VSCE: Dev Client + Attach to Server。
该组合定义在 launch.json 的compounds中,等价于依次执行VSCE: Launch Dev Client与VSCE: Attach to Server。
4.4 其他可用的调试配置
launch.json 中还提供了另外几组与调试测试相关的配置,可配合使用:
VSCE: Launch Prod Client:加载打包产物dist/bin/vscode-ng-language-service/development_package(preLaunchTask为VSCE: package),用于验证接近发布形态的扩展行为;DEBUG: Attach to bazel test:attach 到 9229 端口,用于调试 Bazel 测试进程;DEBUG: Run bazel test (Custom Target):交互式输入 Bazel target 后以--config=debug运行测试,默认//packages/...;DEBUG: Run bazel test (Custom Target) + Attach:两者组合,一条命令跑测试并挂调试器。
五、扩展激活与「trusted workspace」机制
理解扩展如何启动有助于调试。扩展入口 extension.ts 的activate逻辑如下:
- 创建
AngularLanguageClient并注册到context.subscriptions; - 监听配置变更,若涉及启动/会话相关配置(见 config_change.ts),则停止并重启语言服务器;
- 工作区未受信任时进入受限模式:不启动语言服务器、不注册命令,仅在用户授予信任(
onDidGrantWorkspaceTrust)后才启动。这一点与扩展 package.json 中capabilities.untrustedWorkspaces声明「Angular 语言功能在非信任工作区中禁用」相互印证。
客户端实际启动服务器的代码在 client.ts 的start()方法中:通过vscode-languageclient以 IPC 传输方式启动服务器子进程,debug 模式下使用--nolazy --inspect-brk=6009参数与NG_DEBUG=true环境变量;生产模式下则直接加载扩展目录下的server模块。启动参数由constructArgs()根据 VSCode 配置动态拼装,包括--logFile/--logVerbosity(对应angular.log)、--tsdk、--forceStrictTemplates、--suppressAngularDiagnosticCodes、--useClientSideFileWatcher等。
六、测试本地修改:单元测试、LSP 测试与 e2e
除手工验证外,DEVELOPER.md 之外的扩展 package.json 脚本还提供了完整的自动化测试入口:
"test": "bazel test --test_tag_filters=unit_test //vscode-ng-language-service/...", "test:watch": "ibazel test --test_tag_filters=unit_test //vscode-ng-language-service/...", "test:lsp": "bazel test --test_output=streamed //vscode-ng-language-service/integration/lsp:test", "test:e2e": "bazel test --test_output=streamed //vscode-ng-language-service/integration/e2e:test", "test:inspect-client": "bazel run --config=debug //vscode-ng-language-service/client/src/tests:test", "test:inspect-common": "bazel run --config=debug //vscode-ng-language-service/common/tests:test", "test:inspect-server": "bazel run --config=debug //vscode-ng-language-service/server/src/tests:test", "test:inspect-syntaxes": "bazel run --config=debug //vscode-ng-language-service/syntaxes/test:test",- 单元测试:覆盖 client、common、server、syntaxes 四个子包的
unit_test,例如 server/src/tests 下的config_spec.ts、embedded_support_spec.ts、version_provider_spec.ts等; - LSP 集成测试:integration/lsp/ivy_spec.ts 直接面向 LSP 协议层验证语言能力;
- e2e 测试:integration/e2e 中的
completion_spec.ts、definition_spec.ts、hover_spec.ts在真实 VSCode 实例中验证补全、定义跳转与悬停提示。
调试测试时,test:inspect-*系列会以--config=debug运行,配合前面提到的DEBUG: Attach to bazel test(端口 9229)即可在测试进程中打断点。
七、开发工作流总结与常见注意点
把以上内容串起来,一次典型的本地开发迭代是:
- 修改 client 或 server 下的源码;
- 按F5(或选择
VSCE: Launch Dev Client),.vscode/tasks.json中的VSCE: watch bundles会自动以 ibazel watch 模式编译增量产物; - 在启动的开发宿主窗口中复现问题、验证修复;
- 需要单步调试服务器逻辑时,选择
VSCE: Dev Client + Attach to Server一次性拉起客户端并挂接 6009 端口调试器; - 需要验证产物形态时,执行
pnpm --filter=ng-template run package构建.vsix,产物位于./dist/bin/vscode-ng-language-service/ng-template.vsix,可用code --install-extension安装验证; - 提交前运行
pnpm --filter=ng-template run test、test:lsp、test:e2e保证各层测试通过。
最后提醒几个容易踩坑的点:
- 依赖同步:为 server 新增生产依赖时,务必同步根 package.json 与 server/package.json,否则 monorepo 锁文件或打包链路会出现解析失败;
- 调试端口一致:语言服务器调试端口(6009)与 launch.json 中
VSCE: Attach to Server的端口必须保持一致,修改任一处需同步另一处; - 产物目录:一切 Bazel 输出都在
bazel-bin(对应dist/bin软链),调试配置、main入口与打包规则都以此为前提,不要在源码目录中寻找编译产物; - 受信任工作区:在非信任工作区中扩展只会提供语法高亮等受限能力,语言服务器不会启动,调试前请先确认工作区已授予信任。
【免费下载链接】angularDeliver web apps with confidence 🚀项目地址: https://gitcode.com/GitHub_Trending/an/angular
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考