Parcel for VS Code 扩展实战:借助 @parcel/reporter-lsp 在编辑器内联显示构建诊断
【免费下载链接】parcelThe zero configuration build tool for the web. 📦🚀项目地址: https://gitcode.com/gh_mirrors/pa/parcel
Parcel 官方推出的 VS Code 扩展(parcel-for-vscode,显示名为 "Parcel for VS Code")通过语言服务器协议(LSP)将 Parcel 构建过程中产生的错误、警告等诊断信息实时内联展示在编辑器代码行上,并额外提供 Importers 依赖查看视图与.parcelrc配置智能校验。本文以仓库中的 扩展 README 为骨架,结合@parcel/reporter-lsp、@parcel/lsp、@parcel/lsp-protocol的源码实现,完整讲解扩展的安装启用、底层通信架构、诊断流水线、进阶能力与本地调试方法,读者照此即可在自己的 Parcel 项目中获得"构建报错即编辑器内联提示"的零配置开发体验。
扩展是什么:把 Parcel 诊断搬进编辑器
原 README 用一句话概括了该扩展的核心能力:"This extension shows errors, warnings and other diagnostics inline in VS Code."—— 即把 Parcel 在构建(build)、监听(watch)、开发服务器(serve)阶段产生的错误、警告以及其他诊断,直接以编辑器内联标记(squiggle 下划线)的形式显示在对应源码行上,而不再需要切回终端翻看日志。
从 package.json 可以看到扩展的关键元信息:
name:parcel-for-vscode,publisher:parcel,当前仓库版本为2.16.3;engines.vscode:^1.67.0(要求 VS Code 1.67 及以上);activationEvents:onStartupFinished——扩展随 VS Code 启动完成后自动激活,无需手动触发;main:./lib/extension.js,server:./lib/server.js,扩展本体(语言客户端)与语言服务器是两个独立构建目标;- 依赖
vscode-languageclient与@parcel/lsp,通过 LSP 与内置语言服务器通信。
扩展不止提供诊断展示,还贡献了资源管理器中的 "Importers" 视图、Focus in importers view命令,以及.parcelrc/package.json的 JSON Schema 校验(详见后文)。
快速开始:两步接入 LSP 诊断
原 README 的 Usage 章节给出的接入流程非常精简,只有两步:
- 安装扩展:在 VS Code 中安装 "Parcel for VS Code"(本仓库即为该扩展的源码与打包清单)。
- 安装 reporter 并以之运行 Parcel:在项目里安装
@parcel/reporter-lsp,然后带着该 reporter 启动 Parcel。原文档给出的命令示例为:
parcel src/index.html --reporter @parcel/reporter-lspreporter 自己的 README 补充说明,该 reporter 可搭配 Parcel 的 build、watch、serve 三种命令使用,例如:
parcel serve --reporter @parcel/reporter-lsp也可以同时通过--watch等其他 CLI 参数组合使用。--reporter是 Parcel 的通用命令行选项,@parcel/reporter-lsp是一个实现了 Parcel Reporter 插件接口的 npm 包(见 lsp-reporter/package.json,其声明parcel: ^2.16.3的引擎约束),因此也可以把它写进项目的.parcelrc的reporters配置中固定启用,而无需每次敲命令行。
接入完成后,打开 VS Code 并运行上述命令,当代码中出现语法错误、解析失败、依赖缺失等问题时,对应文件行内便会立即出现红色/黄色波浪线,鼠标悬停即可看到与终端一致的诊断详情。
架构拆解:三进程 + 一个 IPC 枢纽
扩展虽小,但背后是一套完整的"LSP 生态",仓库中与之强相关的包一共有四个,各司其职:
| 包 | 位置 | 职责 |
|---|---|---|
parcel-for-vscode(扩展本体) | packages/utils/parcelforvscode | VS Code 语言客户端(LanguageClient)+ Importers 视图 + Schema 校验 |
@parcel/lsp(语言服务器) | packages/utils/parcel-lsp | 真正的 LSP Server,接收 VS Code 请求,转发给 reporter |
@parcel/reporter-lsp(构建侧 reporter) | packages/reporters/lsp-reporter | 在 Parcel 构建进程中收集诊断,推送/应答给语言服务器 |
@parcel/lsp-protocol(协议定义) | packages/utils/parcel-lsp-protocol | 自定义 JSON-RPC 消息类型,双方共用的"契约" |
一条诊断从"构建失败"到"编辑器内联显示"大致经过如下链路:
Parcel 构建进程 (reporter-lsp) │ ① 监听 buildFailure / log / buildSuccess 事件 │ ② 将 Parcel Diagnostic 转换为 LSP Diagnostic(含行号/列号换算) │ ③ 写入工作区诊断 Map ▼ 临时目录 IPC socket(os.tmpdir()/parcel-lsp/parcel-<pid>) │ ④ NotificationWorkspaceDiagnostics / RequestDocumentDiagnostics ▼ LSP Server (@parcel/lsp, lib/server.js) │ ⑤ 按 projectRoot 匹配到对应 reporter 连接,转发请求/通知 ▼ VS Code 扩展(extension.ts 语言客户端) │ ⑥ publishDiagnostics / 诊断刷新 ▼ 编辑器内联波浪线进程间的"信物":临时目录哨兵与元数据文件
两个独立进程(Parcel 构建进程与 VS Code 扩展进程)如何互相发现?答案是操作系统临时目录下的parcel-lsp目录。从 LspReporter.js 的源码可见:
- 通信 socket:
os.tmpdir()/parcel-lsp/parcel-<pid>(按 reporter 所在进程的 pid 命名); - 元数据文件:
parcel-<pid>.json,内容为{projectRoot, pid, argv},供 LSP Server 判断该构建进程属于哪个工作区; - 哨兵文件:
lsp-server,由 LSP Server 启动时写入、扩展停用时删除(见 extension.ts),reporter 用fs.watch监听该文件是否存在,从而只在扩展已激活时才建立 IPC 连接(watchLspActive逻辑)。
LSP Server 侧则在启动时扫描parcel-lsp目录下所有.json元数据,凡projectRoot与自身工作区根目录一致者,即建立一条 JSON-RPC over socket 的客户端连接(见 LspServer.ts),并使用@parcel/watcher监听目录,实现新构建进程的自动接入与进程退出后的自动断开。这种"临时目录 + 哨兵 + 元数据"的设计,使得扩展、LSP Server、任意多个 Parcel 构建进程可以在互不感知对方启动顺序的情况下完成握手。
自定义协议:parcel/request-importers 等五个消息
两个进程之间并非使用标准 LSP 消息,而是基于vscode-jsonrpc定义了五个专属消息类型(见 lsp-protocol 源码):
| 消息 | 方向 | 作用 |
|---|---|---|
parcel/request-importers | LSP Server → Reporter | 请求某文件的导入方(Importers)列表 |
parcel/request-document-diagnostics | LSP Server → Reporter | 请求单个文档的额外诊断(如未使用导出提示) |
parcel/notification-workspace-diagnostics | Reporter → LSP Server | 推送一批工作区诊断 |
parcel/notification-build-status | Reporter → LSP Server | 推送构建状态:start/progress/end |
parcel/notification-build | LSP Server → VS Code 扩展 | 通知一次构建结束(用于清空 Importers 视图) |
LSP Server 对 VS Code 暴露的是标准 LSP 能力(textDocumentSync: Incremental、diagnosticProvider等,见 LspServer.ts),对内则通过findClient按文件路径与各 reporter 的projectRoot做最长公共前缀匹配,把请求转发给正确的构建进程。
诊断流水线:Parcel Diagnostic 到 LSP Diagnostic 的转换
reporter 的核心逻辑在 LspReporter.js 的report()钩子中,它按 Parcel Reporter 插件约定响应各生命周期事件:
watchStart:记录监听已开始,并延迟到确认 LSP Server 在线后才初始化 IPC 服务(doWatchStart),期间还会清理孤儿进程遗留的 socket 文件(通过ps-node校验 pid 是否存活);buildStart:重置诊断 Map 并广播start状态;buildSuccess:resolve bundleGraph,广播end并推送诊断;buildFailure:把event.diagnostics转为 LSP 诊断,广播end并推送;log:当日志带 diagnostics 且级别为 error/warn/info/verbose 时同样收集;buildProgress:把进度换算为可读消息(getProgressMessage)广播;watchEnd:关闭所有连接并清理元数据文件。
行号列号换算与 relatedInformation
关键转换函数updateDiagnostics(LspReporter.js)展示了 Parcel 与 LSP 坐标体系的差异:
- Parcel 的行、列从 1 开始,LSP 从 0 开始,因此转换时执行
line - 1、column - 1(结束列则用column保持开区间语义); - 取第一个 codeFrame 的第一个 codeHighlight 作为主诊断范围,其余 codeFrame/codeHighlight 全部折叠进 LSP 的
relatedInformation数组,从而在 VS Code 的"问题"面板和悬停提示中呈现完整的多文件上下文; - 诊断的
source取diagnostic.origin,消息拼接主消息与首个高亮的消息。
严重级别映射定义在 utils.js:error → Error、warn → Warning、info → Information、verbose → Hint,与 VS Code 四种下划线颜色一一对应。
请求驱动的诊断:未使用导出提示
除构建事件主动推送外,reporter 还实现了parcel/request-document-diagnostics的应答(getDiagnosticsUnusedExports,LspReporter.js):在 BundleGraph 中定位当前文档对应的 asset,调用bundleGraph.getUsedSymbols比对导出符号,对未被使用的 export 生成Unused export.的 Hint 级诊断,并打上DiagnosticTag.Unnecessary标签——这样 VS Code 会以淡化的方式渲染它们,提示可安全删除。该能力依赖 Parcel 的 Symbol Propagation 机制,只有在 reporter 侧持有打包完成的 BundleGraph 时才能工作,因此需要buildSuccess之后才会返回完整结果。
进阶功能:Importers 视图与配置校验
Importers:查看谁在引用当前文件
扩展在资源管理器(Explorer)中注册了名为 "Importers" 的树视图(见 package.json 的 contributes 配置)。打开任意文件后,执行命令面板中的Focus in importers view(命令 IDimportersView.focus),即可看到该文件的所有导入方(谁 import 了它),并支持逐级向下展开形成一棵"依赖我的文件"树。
其实现位于 importersView.ts:视图通过语言客户端向 LSP Server 发送RequestImporters,LSP Server 转发给对应 reporter,reporter 端getImporters(LspReporter.js)在 BundleGraph 上调用getIncomingDependencies拿到所有来源依赖,返回去重后的file://URI 列表。每次构建结束(收到parcel/notification-build)视图会自动清空重建,避免展示过期引用关系。该功能对理解大型项目中的模块耦合、评估重构影响面非常实用。
JSON Schema 校验:.parcelrc 与 package.json
扩展还通过contributes.jsonValidation注册了两份 schema(见 package.json):
.parcelrc→ parcelrc.schema.json,覆盖extends、bundler、resolvers、transformers、validators、namers、packagers、optimizers、compressors、reporters、runtimes等全部 Parcel 配置键,并禁用未知属性(additionalProperties: false),同时把.parcelrc及.parcelrc*关联为jsonc语言,从而在编辑配置时获得补全、校验与默认值提示;package.json→ package-targets.schema.json,对包内的 targets 字段提供结构校验,避免手写入口、输出格式等配置出错。
本地开发与调试:如何跑起并调试这个扩展
仓库中的 vsc-extension-quickstart.md 提供了面向开发者的快速启动指南:
- 在 VS Code 中按
F5,会打开一个加载了本扩展的 Extension Development Host 新窗口; - 在
src/extension.ts中打断点即可调试扩展本体,输出可在调试控制台查看; - 在该新窗口中打开一个 Parcel 项目,运行
parcel src/index.html --reporter @parcel/reporter-lsp(或parcel serve --reporter @parcel/reporter-lsp),即可观察诊断的实时上屏; - 修改
src/extension.ts后可点调试工具栏重启,或按Ctrl+R/Cmd+R(macOS)重载窗口加载新代码。
关于调试模式,extension.ts 中为语言服务器配置了--nolazy --inspect=6009,即以 Node Inspector 模式启动lib/server.js(其内容仅一行import '@parcel/lsp',真正的 LSP Server 实现在 parcel-lsp/src/LspServer.ts),开发者可把调试器附加到 6009 端口深入调试协议层。扩展的测试代码位于 test/suite/extension.test.ts,通过 VS Code 调试视图中的 "Extension Tests" 配置运行。
若想本地打包扩展,package.json的 scripts 提供了yarn run compile(TypeScript 编译)、vsce package --yarn(打包 vsix)等命令,打包前vscode:prepublish会用 Parcel 自身构建扩展产物——恰好体现"用 Parcel 构建 Parcel 扩展"的 dogfooding 设计。
注意事项与适用前提
- 版本匹配:扩展、
@parcel/lsp、@parcel/reporter-lsp、@parcel/lsp-protocol在仓库中均锁定为同一版本(当前为2.16.3)且互相引用,建议在项目中安装与扩展版本一致的@parcel/reporter-lsp,避免协议不兼容;reporter 的引擎约束为parcel: ^2.16.3。 - 工作区匹配:LSP Server 通过
projectRoot精确匹配 reporter(WORKSPACE_ROOT === projectRoot),因此 reporter 应运行在与 VS Code 打开的根目录相同的项目上;多个项目同时构建时,findClient会按路径最长公共前缀选择对应进程。 - 进程生命周期:reporter 在
watchEnd时关闭 IPC 连接并清理元数据;若 Parcel 进程异常退出,LSP Server 的@parcel/watcher监听会将其从客户端表中移除,并推送空的诊断刷新,避免编辑器残留过期波浪线;而 reporter 启动时也会清理孤儿 socket 文件。 - Node 环境:
@parcel/lsp与@parcel/reporter-lsp均要求 Node >= 16,且扩展需要 VS Code >= 1.67。
总体而言,这套方案把"构建诊断"与"编辑器内联"之间的鸿沟用一层轻量 IPC 桥接了起来:扩展侧只负责标准 LSP 交互,构建侧只负责事件收集与坐标转换,双方通过临时目录中的 socket 与哨兵文件解耦,既保持了 Parcel 构建进程的独立性,又让开发者无需离开编辑器即可获得即时、精确到行列的构建反馈。
【免费下载链接】parcelThe zero configuration build tool for the web. 📦🚀项目地址: https://gitcode.com/gh_mirrors/pa/parcel
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考