在 Zed 中配置 Deno 语言支持:语言服务器切换、格式化、配置补全与调试实操指南
本文面向在 Zed 编辑器中编写 Deno/TypeScript 代码的开发者,完整讲解如何通过官方 Deno 扩展启用 Deno Language Server、替换默认的 TypeScript 语言服务器、获得 deno.json/package.json 配置补全,以及配置 .zed/debug.json 调试会话与 .zed/tasks.json 测试任务。内容以仓库文档 docs/src/languages/deno.md 为核心骨架,并结合 Zed 源码中语言服务器解析与设置的实现细节进行补充,保证给出的配置可以直接落地、可验证。
Deno 支持概览
Zed 通过官方 Deno 扩展为 Deno 提供语言支持(扩展可通过 Zed 的 Extensions 面板搜索安装),其语言能力依赖 Deno Language Server(deno lsp)提供:
- 类型检查与诊断:Deno LSP 内置基于 TypeScript 编译器的语义分析;
- 补全与跳转:对本地模块、远程模块(
https://、npm:导入)提供补全、定义跳转与引用查找; - 格式化:通过 LSP 的
textDocument/formatting能力实现deno fmt风格格式化。
从源码结构看,deno 与 typescript-language-server、biome、eslint、tailwind 等一同被列为“可用的语言服务器”之一,例如 crates/language/src/language_settings.rs 的测试 test_resolve_language_servers 就构造了包含 deno 在内的可用服务器集合,验证名称解析逻辑。因此,让 TypeScript/JavaScript 文件使用 Deno 生态,核心工作就是把每个具体语言(JavaScript/TypeScript/TSX)的语言服务器列表切换到 deno,并把格式化交给它。
前置条件
- 安装 Deno CLI:确保
deno命令在你的PATH中,因为 Deno Language Server、后续的调试(runtimeExecutable: "deno")与任务(deno test)都依赖该二进制。 - 安装 Deno 扩展:在 Zed 的扩展市场中安装 Deno 扩展,之后
deno才会被注册为可用的语言服务器名称。
为 JavaScript / TypeScript / TSX 启用 Deno 语言服务器
Zed 对 JS/TS 家族有一套“默认语言服务器”策略。以仓库默认设置 assets/settings/default.json 为例,TypeScript 与 TSX 默认使用 vtsls,并显式禁用 typescript-language-server(列表中 "!typescript-language-server" 即“默认不启用”的写法),同时通过占位符 "..." 表示“其余可用服务器都启用”。
因此,当你要用 Deno LSP 处理 .ts、.tsx(以及 .js)文件时,通常需要同时完成两件事:
- 在
lsp段中给deno服务器下发初始化选项,将deno.enable置为true(Deno LSP 默认不会主动接管文件,需要显式开启); - 在每个语言的
language_servers列表中显式把deno提到前面,并禁用typescript-language-server、vtsls、eslint,避免多个服务器同时做类型检查/诊断造成重复报错。
可以在设置编辑器(zed::OpenSettings)的 Languages > JavaScript / TypeScript / TSX 下操作,也可以直接在 settings 文件中加入以下完整配置:
{
"lsp": {
"deno": {
"settings": {
"deno": {
"enable": true
}
}
}
},
"languages": {
"JavaScript": {
"language_servers": [
"deno",
"!typescript-language-server",
"!vtsls",
"!eslint"
],
"formatter": "language_server"
},
"TypeScript": {
"language_servers": [
"deno",
"!typescript-language-server",
"!vtsls",
"!eslint"
],
"formatter": "language_server"
},
"TSX": {
"language_servers": [
"deno",
"!typescript-language-server",
"!vtsls",
"!eslint"
],
"formatter": "language_server"
}
}
}
关键字段语义
| 配置 | 含义 | 备注 |
|---|---|---|
lsp.deno.settings.deno.enable |
是否让 Deno LSP 接管文件 | 置 true 后 Deno 才会做类型检查与补全 |
language_servers 中的 "deno" |
显式启用并调整顺序 | 列表靠前 = 优先级更高 |
"!typescript-language-server" / "!vtsls" / "!eslint" |
前缀 ! 表示“从该语言启用集合中排除” |
与默认值中的 ! 前缀写法一致 |
formatter: "language_server" |
使用该语言启用的 LSP 提供的格式化能力 | 等价于执行 Deno 的格式化接口 |
"..."(占位符) |
代表“其余所有可用语言服务器” | 不使用则不会自动带入 tailwind 等其余服务器 |
关于 ! 前缀与 "..." 占位符的精确语义,可直接在源码测试中找到验证。例如 crates/language/src/language_settings.rs 的 test_resolve_language_servers 证明:
- 单独
["..."]等于启用全部可用服务器; - 显式引用某个名称(如把
deno写在后面)会改变它在结果中的顺序; "!name"会把对应服务器从结果中移除;- 列表中出现一个尚不可用的新名称会把它追加进去。
再如 crates/settings_content/src/language.rs 的合并测试表明:用户在某个语言下配置的 language_servers 列表会整体替换该语言默认列表——这正是本文配置能够把默认的 vtsls 换成 deno 的机制来源。注意,!vtsls 这类“否定”条目在合并时只对该层生效,不会反向污染全局默认(同文件 crates/settings_content/src/language.rs)。
如果你的项目仍需要保留 ESLint 的某些能力,但不想让它在类型层与 Deno 冲突,可以从列表中去掉 "!eslint" 甚至去掉 "!typescript-language-server",仅保留 "!vtsls";更复杂的语言服务器与格式化组合方式(如 formatter 的可选值 "auto"、"language_server"、"prettier"、基于 code action 的 "source.fixAll.eslint" 等)参见默认设置 assets/settings/default.json 中的示例注释,以及 配置受支持的语言 文档。
为 deno.json / package.json 提供配置补全
启用 Deno LSP 只是第一步。deno.json / deno.jsonc 是 Deno 工程的重要配置文件,Zed 通过 JSON 语言服务器(json-language-server)提供它们的补全与校验。为它们绑定 JSON Schema,需要在 settings 文件中给 json-language-server 下发如下 schemas 配置:
"lsp": {
"json-language-server": {
"settings": {
"json": {
"schemas": [
{
"fileMatch": [
"deno.json",
"deno.jsonc"
],
"url": "https://raw.githubusercontent.com/denoland/deno/refs/heads/main/cli/schemas/config-file.v1.json"
},
{
"fileMatch": [
"package.json"
],
"url": "https://www.schemastore.org/package"
}
]
}
}
}
}
fileMatch 声明了该 Schema 要匹配哪些文件名,url 指向 Schema 来源:
deno.json、deno.jsonc使用 Deno 官方维护的config-file.v1.jsonSchema(随 Deno 主仓库演进,url 中的refs/heads/main表示跟随主干);package.json使用 JSON Schema Store 的通用 package 规范,便于在 npm 项目中获得补全与校验。
配置完成后,打开 deno.json 即可获得 tasks、imports、compilerOptions 等字段的智能补全与非法值提示;若你是将 schema 通过其他方式(如语言服务器扩展)注入的,也可以忽略此节。更多 JSON Schema 配置背景参见 JSON 语言支持文档。
与 Zed 内置 Schema 机制的关系
从源码结构看,Zed 自身在 crates/json_schema_store/src/json_schema_store.rs 维护了一套 zed://schemas/ 前缀的内置静态 Schema(如 tsconfig.json、package.json 的本地副本)供设置文件、任务文件等使用;而本节配置的作用对象是 json-language-server 自身的 LSP 设置,面向的是项目中的普通 JSON 文件。两者互补:前者管 Zed 自己的配置界面,后者管你的 Deno/npm 工程文件。
DAP 支持:调试 Deno 程序
Zed 内置 JavaScript 调试适配器,可在 .zed/debug.json 中定义一个基于 Node 调试协议(pwa-node)的 Deno 启动配置。将以下内容加入项目根目录的 .zed/debug.json:
[
{
"adapter": "JavaScript",
"label": "Deno",
"request": "launch",
"type": "pwa-node",
"cwd": "$ZED_WORKTREE_ROOT",
"program": "$ZED_FILE",
"runtimeExecutable": "deno",
"runtimeArgs": ["run", "--allow-all", "--inspect-wait"],
"attachSimplePort": 9229
}
]
字段说明如下:
| 字段 | 值 | 含义 |
|---|---|---|
adapter |
"JavaScript" |
使用 Zed 内置的 JS 调试适配器(对应 crates 中 dap 相关实现) |
label |
"Deno" |
在调试会话列表里显示的名称 |
request |
"launch" |
启动(而非 attach)模式 |
type |
"pwa-node" |
复用 Node.js 的 pwa-node 调试会话类型 |
cwd |
"$ZED_WORKTREE_ROOT" |
工作目录 = 当前工程根目录 |
program |
"$ZED_FILE" |
启动入口 = 当前激活文件(即你要调试的 .ts) |
runtimeExecutable |
"deno" |
用 deno 作为运行时,而非 node |
runtimeArgs |
["run", "--allow-all", "--inspect-wait"] |
运行参数:run 执行脚本、--allow-all 放开权限、--inspect-wait 等待调试器接入后再执行 |
attachSimplePort |
9229 |
以简单 attach 方式连接 9229 端口(Deno 默认 --inspect 端口) |
关于 .zed/debug.json 的通用机制可参考 调试器文档:它应放在项目根目录并存放“配置对象数组”;Zed 也会读取 .vscode/launch.json;若要在多个项目间复用同一套调试配置,可通过命令面板调用 zed::OpenDebugTasks 打开用户级 debug.json(macOS 位于 ~/Library/Application Support/Zed/debug.json,Linux/BSD 位于 $XDG_CONFIG_HOME/zed/debug.json,Windows 位于 %APPDATA%\Zed\debug.json),其中场景会自动合并到每个工作区。
配置完成后,把当前文件切换到待调试的入口 .ts,打开“New Debug Session / 新调试会话”对话框即可看到 Deno 配置,启动后可命中断点、单步调试。
调试运行原理解读
该配置的关键在于 runtimeArgs 与 attachSimplePort 的组合:deno run --inspect-wait 会让 Deno 进程启动后暂停等待调试器客户端在 9229 端口接入(等待期间不会先执行代码,避免错过启动期断点),而 attachSimplePort: 9229 正是让 Zed 去 attach 这个端口。相比直接 deno run,这种“启动并等待调试器”的方式对程序入口处的断点最为可靠。
Runnable 支持:把 Deno 测试接入 Zed 任务系统
把 deno test 接入 Zed 的任务与测试 UI,可在项目根目录的 .zed/tasks.json 中加入:
[
{
"label": "deno test",
"command": "deno test -A $ZED_FILE",
"tags": ["js-test"]
}
]
字段说明:
label:任务在 UI 中的显示名;command:实际执行的 shell 命令。-A等价于--allow-all(放开全部权限),$ZED_FILE是 Zed 注入的环境变量,代表当前激活文件,因此该任务会运行“当前打开文件”对应的测试;tags: ["js-test"]:将任务归类为 JS 测试任务,使其出现在 Zed 的测试运行器(Run Tests)相关入口中,配合js-test/js-test-single等标签可实现可发现性与一键执行。
配置后可打开的交互入口包括:命令面板中的 Run Task、编辑器上下文、以及测试相关面板;Zed 的任务定义与 $ZED_* 变量体系详见 tasks 相关文档 中对 cwd 默认取 $ZED_WORKTREE_ROOT、构建任务可引用 $ZED_FILE 的说明。同理,若只想针对当前文件运行单个测试,可将命令改为 deno test -A --filter <pattern> $ZED_FILE,并把 pattern 动态拼接进命令。
常见问题与调试建议
- 切换后仍出现 vtsls 报错:确认各语言的
language_servers中确实保留了"!vtsls"/"!typescript-language-server"条目;用户级配置的列表会整体替换语言默认列表(合并语义见上文源码测试),若只写了["deno", "..."],则其余服务器仍会参与。 deno.json没有补全:确认json-language-server的schemas已配置且文件名与fileMatch完全一致(注意deno.jsonc与deno.json都要列出);也可在 Languages 设置中检查 JSON 语言是否启用了json-language-server。- 调试启动即报“找不到模块/权限错误”:检查
deno是否在 PATH 中、cwd是否解析到工程根目录;需要网络下载依赖时建议保留--allow-all或收敛为--allow-net等最小权限集。 - 任务里
$ZED_FILE为空:该变量只有在“编辑器中有激活文件”的任务触发路径下才有值;从全局(无文件)上下文触发的任务请改用$ZED_WORKTREE_ROOT定位文件。
相关文档
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00