VS Code 主题:从手写 JSON 到可发布
📚 系列导航
本系列共五篇,覆盖从零基础创建到工业级设计系统的 VS Code 主题开发全流程(对应 Moongate v2.6.0):
VS Code 主题:从手写 JSON 到可发布 —— 不依赖脚手架,手写最小主题 JSON,掌握
colors与tokenColors的核心机制与发布流程。主题工程化:从单体 JSON 到模块化 YAML —— 将单体 JSON 重构为模块化 YAML 项目,用构建脚本实现变量替换与自动生成。
设计系统:DTCG 三层架构与昼夜双变体 —— 用 DTCG 设计令牌标准管理颜色,通过语义层与重力补偿构建深色/浅色双变体。
构建体系:可测试、可验证的工程实践 —— 模块化构建体系、WCAG 对比度校验、scope 自动验证、自动化测试与多格式产物生成。
品牌生态:设计哲学与视觉契约 —— 为你的主题赋予设计哲学、视觉契约和品牌生态,打造完整的设计系统。
如果你有编程基础(熟悉 JavaScript、JSON、命令行),想把一套配色方案变成 VS Code 主题,但完全不知道从何下手——这篇文章正是为你准备的。
Moongate 主题最初就是从个人博客的配色衍生而来。在这篇文章中,我们不使用任何脚手架,而是从一个最小的 JSON 文件开始,逐步理解主题的运作机制。等机制清楚了,你自然会发现哪些环节需要工程化——那就是整个系列接下来要做的事。
一、VS Code 主题的本质
一个主题说到底就是一份 JSON 文件,它告诉 VS Code 两件事:
- 界面长什么样:标题栏、状态栏、侧边栏、编辑器背景……这些 UI 区域的颜色。
- 代码怎么着色:不同的语法元素(关键字、字符串、注释、函数……)分别用什么颜色和样式。
理解文件结构本身并不难,真正难的是知道该配置哪些键名、每个键名是什么意思。所以这篇文章的核心目标是:带你亲手创建一个最小可用的主题,然后告诉你如何用 VS Code 自带的工具,找到任何你想调整的颜色所对应的正确键名。
二、自定义主题的最小路径
1. 创建项目结构
首先准备一个空目录,并创建 themes/ 文件夹:
mkdir my-theme
cd my-theme
mkdir themes
虽然 VS Code 的扩展项目通常还需要 package.json、README.md 等文件,但为了让读者先专注理解结构,这里从主题 JSON 本身开始。
2. 编写最小主题 JSON
在 themes/ 下创建一个 JSON 文件,例如 my-theme.json:
{
"name": "My Theme",
"type": "dark",
"colors": {
"editor.background": "#0f172a",
"editor.foreground": "#e2e8f0"
},
"tokenColors": [
{
"name": "Comment",
"scope": ["comment", "punctuation.definition.comment"],
"settings": {
"fontStyle": "italic",
"foreground": "#a5b4cb"
}
},
{
"name": "Keyword",
"scope": ["keyword", "storage.type", "storage.modifier"],
"settings": {
"foreground": "#3b82f6",
"fontStyle": "bold"
}
},
{
"name": "String",
"scope": ["string", "string.quoted.single", "string.quoted.double"],
"settings": {
"foreground": "#34d399"
}
}
]
}
这个文件虽然很小,但它已经包含了主题的全部核心结构。
三、核心概念:colors 与 tokenColors
colors:编辑器界面
colors 对象定义编辑器 UI 的配色——背景、标题栏、状态栏、侧边栏、选区高亮等。它是一个扁平的对象,键名是 VS Code 预定义的接口,例如:
| 键名 | 作用 |
|---|---|
editor.background |
编辑器背景 |
editor.foreground |
编辑器默认前景色 |
titleBar.activeBackground |
标题栏背景 |
statusBar.background |
状态栏背景 |
sideBar.background |
侧边栏背景 |
⚠️
type字段:顶级type字段决定主题是深色还是浅色,取值为"dark"或"light"。它会影响 VS Code 默认控件的渲染方式(如滚动条、输入框的自适应)。
tokenColors:代码语法高亮
tokenColors 是一个规则数组,每条规则由 scope 和 settings 组成:
scope:匹配的 TextMate 作用域(scope),可以是字符串或字符串数组。settings:该作用域应用的颜色与样式(foreground、fontStyle、background)。
{
"name": "Comment",
"scope": ["comment", "punctuation.definition.comment"],
"settings": {
"fontStyle": "italic",
"foreground": "#a5b4cb"
}
}
⚠️ 重要:tokenColors 数组的顺序很重要——后面的规则会覆盖前面相同 scope 的规则。这也是为什么工程化之后我们会用一个独立的 base.yaml 管理通用规则,再在语言文件中叠加专属规则。
四、如何找到正确的键名?
这是所有主题开发者最常遇到的问题:「我想把状态栏文字改成蓝色,该用什么键名?」
VS Code 提供了两个非常强大的内置工具,彻底解决了这个问题。
1. UI 颜色:提取当前主题
按下 Ctrl+Shift+P,运行命令 Developer: Generate Color Theme From Current Settings。
这会在输出面板中生成一个 JSON,包含当前主题所用到的所有 UI 颜色键名以及它们的值。你只需要:
- 在输出中找到你关心的区域(比如
statusBar.foreground)。 - 复制这个键名,粘贴到你自己的
colors对象中。 - 改成你自己的颜色值。
这个命令生成的是「当前生效值」,即使某个键名你从未配置过(VS Code 在使用默认值),它也会出现在输出中——相当于一份完整的键名清单。
2. 语法 scope:Inspect 工具
这是定位语法高亮问题的神器。打开任意代码文件,把光标放在你想着色的元素上,运行 Developer: Inspect Editor Tokens and Scopes。
弹出的窗口会显示:
- 该元素当前的 TextMate scope 链,从最具体到最通用。
- 当前颜色来自哪条规则(
foreground来源),以及是哪个文件定义的。
使用技巧:
- 选择最具体的 scope 来精确命中目标元素,避免误伤同一族元素。
- 例如注释既有
comment.line也有comment.block,如果你只想给行注释着色,就选comment.line;如果想统一处理所有注释,就选comment。 - 当你发现某个元素颜色「不对」时,Inspect 窗口会直接告诉你当前颜色来自哪个规则——这排查思路清晰得多。
五、本地调试
在确认主题文件书写正确后,下一步就是把它加载进 VS Code 实时查看。
1. 创建 package.json
要运行主题扩展,需要一个最小的 package.json 将它声明为扩展:
{
"name": "my-theme",
"displayName": "My Theme",
"version": "0.0.1",
"publisher": "your-name",
"engines": {
"vscode": "^1.109.0"
},
"categories": ["Themes"],
"contributes": {
"themes": [
{
"label": "My Theme",
"uiTheme": "vs-dark",
"path": "./themes/my-theme.json"
}
]
}
}
关键字段:
contributes.themes:声明主题列表,每项包含label(在颜色主题列表中显示的名称)、uiTheme(基础色系:vs-dark深色 /vs浅色)、path(主题 JSON 的相对路径)。publisher:你的发布者 ID。可以先填占位符,发布前注册后再回来修改。engines:最低 VS Code 版本要求。
2. F5 启动扩展开发主机
- 在 VS Code 中打开项目文件夹。
- 按
F5,启动「扩展开发主机」窗口。 - 在开发主机中按
Ctrl+K Ctrl+T,选择你的主题。 - 打开测试代码文件,实时查看效果。
修改主题 JSON 后,在开发主机中按 Ctrl+R 重新加载,修改立即生效。注意:修改 package.json 中的 contributes.themes 后,需要重启开发主机会话才能生效。
六、准备发布
1. 完善 package.json
发布之前,需要补全关键字段:
{
"name": "my-theme",
"displayName": "My Theme",
"description": "简短介绍你的主题",
"version": "1.0.0",
"publisher": "你的发布者ID",
"engines": { "vscode": "^1.109.0" },
"categories": ["Themes"],
"icon": "images/icon.png",
"repository": {
"type": "git",
"url": "https://github.com/yourname/my-theme"
}
}
2. 准备截图
在根目录创建 images/ 文件夹,放入至少 3-5 张不同语言的代码截图(建议 1280×640),用于 README 和商店展示。
3. 编写 README.md
包含主题名称、预览截图、设计理念、安装方法、配色表(可选)等。
4. 添加 LICENSE
建议使用 MIT 许可证,创建 LICENSE 文件。
5. 创建 .vscodeignore
排除不需要打包的文件,但务必保留 images/ 文件夹:
.vscode/**
.gitignore
node_modules
七、发布前检查清单
在运行 vsce package 之前,花两分钟核对以下事项,可以避免大部分常见的发布错误:
package.json信息:确保publisher、name、version字段正确无误(publisher必须与你在市场注册的 ID 完全一致)。- 图标文件:确认
icon路径指向一个 128×128 像素的 PNG 图片,且文件确实存在于该位置。 - 预览图:检查
README.md中是否包含了至少一张主题预览图(建议使用images/文件夹内的截图),没有预览图的主题很难吸引用户。 .vscodeignore配置:确认已排除不必要的文件,但务必保留images/文件夹,否则截图无法随扩展一起发布。- 本地打包测试:运行
vsce package命令,若能成功生成.vsix文件,说明配置基本正确。如果失败,仔细阅读错误提示——最常见的原因是icon路径错误或publisher未设置。
八、打包与发布
1. 安装发布工具
npm install -g @vscode/vsce
2. 打包测试
vsce package
如果成功,会生成 .vsix 文件。可以拖进 VS Code 手动安装测试。若失败,仔细阅读错误提示,常见原因是 icon 路径错误或 .vscodeignore 误排除了必要文件。
3. 获取 Personal Access Token
- 登录 Azure DevOps(用你注册市场的微软账号)。
- 右上角头像 → Personal access tokens → New Token。
- 名称随意,组织选 All accessible organizations,有效期建议 1 年。
- 权限:只勾选 Marketplace → Manage。
- 创建后立即复制 Token(只显示一次)。
4. 登录并发布
vsce login 你的发布者ID
# 粘贴刚才的 Token(不会显示,直接回车)
vsce publish
几秒后主题就会上传。约 5-10 分钟即可在 VS Code 中搜索到。
常见发布错误:
Token verification failed:权限未正确设置或 Token 过期,重新生成。Version already exists:版本号重复,更新package.json中的version。- 网络问题:尝试更换网络或使用代理。
🔁 替代方案:手动上传 .vsix 文件
如果你在命令行方式中遇到困难,完全可以通过浏览器手动上传:
- 首先确保你已经运行
vsce package成功生成了.vsix文件。 - 访问 VS Code 市场管理页,用你的微软账号登录。
- 在页面中点击你的发布者名称,进入发布者管理界面。
- 点击右上角的 Publish extension 按钮。
- 选择你的
.vsix文件上传。 - 几分钟后主题就会出现在市场中。
优点:完全绕过命令行 token 验证,过程可视化。
九、发布后
- 查看市场页面:
https://marketplace.visualstudio.com/items?itemName=你的发布者ID.你的主题名 - 登录 市场管理后台 查看报表(页面浏览、安装量、转化率)。
- 在 GitHub 仓库添加 README 徽章(如版本、下载量)。
- 收集反馈,准备后续更新。
十、设计哲学:从「好看」到「好用」
很多新手以为主题就是配几个好看的颜色。但真正优秀的主题,能让代码的结构自己「浮现」出来。这就是 「视觉远近法」 的理念:
- 操作符、标点应该退后(亮度低一些),不干扰阅读;
- 函数名应该发光(亮度高一些),成为视觉锚点;
- 只读变量应该用斜体暗示「不可变」;
- 废弃代码应该加上删除线,一眼识别。
这套原则在 Moongate 中落地为「语义分层」:前景(核心逻辑)、中景(普通代码)、背景(辅助信息)三个视觉层级。你可以在后续的系列文章中看到它如何演变为完整的设计体系。
为什么手写 JSON 不可持续?
现在你已经拥有一个可以手动编辑、可以发布的 VS Code 主题了。但当你认真用起来,很快就会遇到这些痛点:
- 一个 JSON 文件动辄上千行,修改一个颜色需要全局搜索,容易误改。
- 想为不同语言定制高亮,却要在同一个
tokenColors数组里堆砌规则,难以维护。 - 想尝试浅色版本,不得不复制整个文件,然后手动修改几百个颜色值。
- 一个不小心,就会用错 scope,某个语言的高亮「规则写了对不上」。
这些问题不是你的失误,而是手写 JSON 这种工作方式的极限。这正是我们接下来的系列要解决的问题——从工程化到设计系统,让主题维护变得轻松而优雅。

