资讯动态

Sketch与JSON互转:设计稿版本管理与自动化实践

发布时间:2026/10/14 19:48:49 来源:尧图企业网站定制
简介sketch-json-cli 是一款面向设计师、前端开发者及需要版本管理设计稿的团队的命令行小工具可将 Sketch 草图文件转换成 JSON也能从 JSON 反向生成草图文件适用于设计稿纳入 Git 管理、自动化生成组件数据等场景。资源包共包含 8 个文件压缩后体积约 34KB主要文件类型包括核心 JavaScript 脚本、示例 JSON 数据、YAML 配置文件、Markdown 说明文档以及 license 许可文件等体量小巧、结构清晰便于直接阅读源码。目前已有 390 人学习适合希望理解 Sketch 文件结构并尝试自动化流程的读者。通过查看 index.js 与相关配置可以掌握命令行工具的参数解析与文件转换机制安装后在终端执行 sketch-json 命令即可完成双向转换方便将设计流程接入脚本化与 CI 构建减少手动重复操作提升团队协作效率。1. 草图文件与 JSON 互转为什么我会把设计稿塞进纯文本里很多刚接触设计稿自动化的同学会问Sketch 文件明明是一份带图形、图片、样式的设计稿为什么非要把它转成 JSON转成 JSON 又图什么先说结论Sketch 文件本身就不是一个二进制黑匣子它内部就是一份有规则的 JSON 数据外面套了个 zip 壳。sketch-json-cli 干的事情就是把壳剥开把 JSON 拿出来给你改、给你 diff、给你版本管理改完再重新装上壳变成可打开的草图文件。适合的人是设计师、前端工程师、自动化测试和搞 CI 构建的同事——但凡你被“设计稿改了但没人知道改了哪里”坑过这个方向就值得投入。至于“json 用什么打开”这类基础疑问读完这篇文章你会有完全不同的答案。2. Sketch 文件剥掉外壳zip 包里的 JSON 世界2.1 先看清 Sketch 文件的结构一个 zip 包里三层内容我最早接触 Sketch 文件转 JSON是因为项目里设计稿版本管理全靠人肉对比每次对接设计师就像在猜谜。后来我用 zip 工具直接解压过一份.sketch文件才彻底明白这东西的内部逻辑。Sketch 文件本质上是一个 zip 压缩包解压后通常能看到这几层内容document.json整个文档的核心数据图层树、样式、布局、文本内容全在这里meta.json文档版本信息、格式版本号、兼容性标记user.json用户视角的状态数据比如当前打开了哪个画板、视图缩放比例pages/或/pages目录旧版本里每个页面是独立的 JSON 文件新版本则合入了document.json的pages数组images/目录引用的位图资源PNG、JPG 都在这里previews/目录Sketch 在 Finder 或图库里显示的预览缩略图。所以“把草图文件转换为 json”这句话拆开来说就是把 zip 解包、把document.json提取出来、或者把整个包的内容展开成可读的 JSON 文件集合。反向操作就是把这些 JSON 内容重新打包成 zip再命名成.sketch后缀。理解这一层结构是所有操作的前提。因为当你只修改document.json试图加一个图层时如果忘记同步meta.json里的版本信息或者丢掉了images/里的图片资源打包出来的文件要么打不开要么打开后图片全部裂开。sketch-json-cli 这类工具的核心职责是帮你把这几层的依赖关系处理好而不是简单做一次“文件格式转换”。2.2 安装 sketch-json-cli 与转换的最小配置安装这一步需要区分两件事你是在本地手工操作还是要在自动化流水线里使用。我自己的经验是本地用 npm 全局安装即可CI 里则建议用npx直接调用避免污染构建环境。常见做法是先把 Node.js 环境备好然后执行npm install -g sketch-json-cli sketch-json-cli --help先别急着转文件。--help输出会列出这个 CLI 支持的子命令不同维护者发布的版本子命令命名有差异。常见的有convert、restore、export、extract等。我一般会用sketch-json-cli --help确认当前版本的实际命令再动手避免记错子命令名导致“命令不存在”的尴尬。配置文件方面多数实现支持在项目根目录放一个.sketchjsonrc或使用命令行参数指定行为。比如指定输出目录、是否保留分页、是否解包图片资源。一个最小可用的调用方式通常是sketch-json-cli convert design.sketch --output ./json-output这条命令把design.sketch解包并转换成 JSON 输出到./json-output目录。注意这里的关键点convert转换出来的不只是一个document.json文件而是整个文件集合——meta.json、user.json和图片资源都在输出目录里。如果你只想拿纯 JSON 数据做 diff可以把images/和previews/排除掉只保留 document、meta、user 三个 JSON 文件。参数上我会关注三个--output指定输出路径目录不存在时工具会自动创建--pretty或--format控制缩进默认是紧凑型输出人眼查看时很难受建议开启格式化方便 diff--skip-resources跳过图片资源导出只导出 JSON 部分。为什么默认不跳过资源因为反向转换时图片资源如果缺失Sketch 打开文件后会提示资源丢失。你当然可以在还原时让工具忽略缺失资源但结果是画板里的位图全部变成灰色占位块。所以除非你确认 JSON 里没有位图引用否则别跳得过猛。2.3 转换前的环境检查版本、class 映射与资源引用很多人在第一步就翻车不是命令不对而是环境不兼容。Sketch 文件格式有过多次变更尤其是 43 版本、50 版本、70 版本这几个节点文件内部结构差异很大。sketch-json-cli 对老版本格式的支持往往依赖第三方解析库而这些库对“新版 document.json 里某些字段从pages独立文件迁移到 pages 数组”这类变化处理得并不完全一致。所以转换之前我建议先做三件事。第一确认 Sketch 文件本身的版本。魔数检查或直接解压看meta.json里的appVersion字段最直观unzip -p design.sketch meta.json | head -n 20如果appVersion是 70 以上但你的 sketch-json-cli 依赖的解析库还是旧逻辑转换出来的pages字段可能会是空数组或者结构错位。第二确认命令行工具的版本号别拿一年前装好的全局包对付最新的设计稿。第三确认图片资源没有外部引用。有些设计稿里的图片是“链接到文件”模式JSON 里保存的只是文件路径并没有把图片打进 zip。这类引用在你转 JSON 到另一台机器时百分百会断。另外要注意 class 映射问题。Sketch 文档里每个图层对象都有一个_class字段比如MSTextLayer表示文本图层MSShapeGroup表示形状组MSArtboardGroup表示画板。sketch-json-cli 的解析能力就体现能不能正确识别这些 class 并还原成可编辑对象。转换前看一眼前面--help的输出有没有提到支持图层类型清单比猜要靠谱得多。提示不要用“只要命令能跑通就代表转换成功”来判断结果。Sketch 打开还原后的文件如果不报错只能代表格式合法不代表图层树、样式、文本内容都完好无损。验证必须靠打开文件人工检查或者用sketchtool导出预览图做像素级对比。3. 把草图文件转成 JSON逐页导出与字段是做什么的3.1 sketch→json 的转换脚本与分页处理在讲具体脚本前先说清楚一个概念Sketch 文件里的“页面”和很多人理解的“画板”是两回事。页面对应的是 Sketch 左侧栏顶部的页面切换一个文件可以包含多个页面每个页面内再放多个画板。转换 JSON 时页面结构直接对应 JSON 数组。如果你在 CI 里要做页面级别的对比必须把这一层结构保留住。从 CLI 执行转换是这样sketch-json-cli convert ./prototype.sketch --output ./converted --pretty这段命令的重点是--pretty。紧凑的 JSON 对程序友好但对人完全不友好。开了格式化之后你才能用肉眼去读document.json找图层。执行完转换后的产物document.json里一般是一个巨大的对象pages数组在根部。这个数组里每个元素就是一个页面页面对象的layers数组里才是画板、文本、形状这些实际图层。如果你需要按页面拆分文件节省后续处理的资源消耗可以在命令后加一个分页参数具体参数名以你装的工具的--help为准。有些实现是--split-pages有些是--page-output本质上都是告诉工具不要把所有页面写进一个document.json而是每个页面单独生成一个 JSON 文件。从原理上讲CLI 内部做的事无非三步unzip design.sketch -d temp_dir python3 split_pages.py temp_dir/document.json temp_dir/pages/ python3 merge_meta.py temp_dir拆解这一步的话split_pages.py干的就是把document.json里的pages数组一个个拎出来每个数组元素写成一个独立 JSON 文件同时保留它们在document.json中的索引位置方便后续还原时按顺序合并回去。这个脚本完全可以自己写我有时候嫌 CLI 输出的结构不满足需求就直接在它基础上做二次处理。整个过程有一个关键的逻辑点页面拆分不是简单地把数组切片。Sketch 的pages里每个页面元素包含do_objectID对象唯一标识、name页面名称、layers图层数组。拆分后必须把do_objectID记录下来因为meta.json和user.json里可能有对特定页面 ID 的引用比如当前选中了哪个页面。拆完不管这个过程还原时页面选中状态就可能丢失。3.2 解读转换结果从 pages 数组找到你的图层转换完成后打开document.json你会面对一棵非常深的 JSON 树。这一节帮你拆解你最常见的几个字段。先看一段经过格式化的 JSON 片段这是仿照常见结构写的示例不是某个真实文件{ _class: document, do_objectID: A1B2C3D4-1234-5678-9ABC-DEF012345678, pages: [ { _class: page, do_objectID: PAGE-ID-001, name: 首页, layers: [ { _class: artboard, do_objectID: ART-ID-001, name: 登录, frame: { x: 0, y: 0, width: 375, height: 812 }, layers: [] } ] } ] }这段 JSON 的本质是一个文档对象根部是pages数组每个页面有自己的layers数组。artboard是画板对象frame定义它的位置和尺寸。这个过程如果你熟悉 DOM 树会感到很亲切document 是根节点page 是 sectionartboard 是 container再往下就是具体的文本节点和形状节点。在转 JSON 之后我要做的最常见的操作是“找文本”。Sketch 里文本图层是MSTextLayer它有一个attributedString字段里面嵌套了string值存的就是实际显示的文字。我写脚本扫描所有页面、所有图层凡是_class等于MSTextLayer的就把attributedString.string打印出来。这个操作在“设计师临时改了文案但没同步给开发”的场景中极其常用效果类似数据库查询import json with open(document.json, r, encodingutf-8) as f: doc json.load(f) def walk_layers(layers, found): for layer in layers: if layer.get(_class) MSTextLayer: text layer.get(attributedString, {}).get(string, ) found.append({id: layer.get(do_objectID), name: layer.get(name), text: text}) walk_layers(layer.get(layers, []), found) all_texts [] for page in doc.get(pages, []): walk_layers(page.get(layers, []), all_texts) for item in all_texts: print(item[name], :, item[text])这段代码做了三件事加载 JSON 到内存递归遍历每一层级筛选出MSTextLayer记录文本内容和对象 ID。walk_layers函数里先处理当前图层再递归进入它的layers所以不管嵌套多深都能遍历到。输出的do_objectID可以用来在反向转换时精确指认要改哪个图层。要注意的是Sketch 文本图层的attributedString结构在不同版本里并不一致。旧版本直接有string有些版本则把它包在attributedString.attributes里。这也是为什么我强调要先把转换结果打开看一遍用自己的文件确认字段路径再写自动化脚本。4. 把 JSON 转回草图文件逆向映射与打包复原4.1 json→sketch 的还原脚本与必须保留的资源文件正向转换是把 zip 拆开读 JSON逆向就是把 JSON 重新组装成 zip。这个过程的坑比正向多得多因为你不光要把document.json写回原位还要保证meta.json、user.json、images/、previews/都回到正确的位置。缺少任何一个关键文件Sketch 都可能拒绝打开。CLI 的还原调用一般是这样的sketch-json-cli restore ./converted --output ./restored.sketch如果转换时用了--split-pages把页面拆成了多个文件还原命令通常需要额外指定页面目录的位置或者它通过配置文件状态自动找回来。我在实际使用中发现不指定分页合并参数的时候一些实现会把所有页面写回一个document.json但页面的排序可能依赖文件名前缀如果你的文件名上没用001_、002_这种序号排序就会乱。还原时最重要的原则是资源文件与 JSON 必须来自同一个转换结果。所以我一般会把converted目录原封不动保留整个images/目录一起交给还原工具。如果只把document.json拿到另一个目录里还原工具会提示图片缺失最终产物是一个没有位图的空壳文件。为了弄清楚还原到底做了什么我建议你在临时目录里手工模拟一遍核心流程mkdir -p temp_restore cp converted/*.json temp_restore/ cp -r converted/images temp_restore/ cd temp_restore zip -r restored.sketch .这段命令把 JSON 和图片拷贝到同一目录然后整体压缩成 zip把后缀改成.sketch。手工执行一次你就会明白还原的实质是把转换结果的目录树重新压缩。CLI 里的restore命令只是把这个过程包装得更友好自动处理了previews/缩略图的重新生成、zip 内部文件顺序等细节。但为什么我不建议长期用手工 zip 方式因为 zip 压缩的文件顺序、压缩算法的选择、meta.json里的信息完整性这些都会影响 Sketch 是否能正确识别。CLI 的restore命令会用与 Sketch 兼容的打包方式重新生成文件如果你用系统自带 zip 命令winzip 或 mac 的归档工具压缩出来的 zip 里有额外隐藏文件Sketch 就可能读不了。4.2 图层 ID 与类名的核对清单改什么字段才会生效从 JSON 改回 Sketch 文件最容易踩的坑是我改了 JSON 但打开后没变化。这张对照表来自我自己的血泪经验告诉你哪些字段改动后会生效哪些是冗余的字段作用改完是否生效do_objectID图层唯一标识建议不要改很多引用依赖它name图层名称即时生效frame.x/y/width/height位置和尺寸即时生效attributedString.string文本内容即时生效但注意文字长度变化后可能溢出style.borders/fills样式属性生效但颜色类型需与_class匹配layerStyle/sharedStyleID共享样式引用部分生效依赖meta.json中的共享样式表这份清单的关键是第四行改文本内容。文本是设计稿改版中最常见的修改点把“立即购买”改成“马上抢”这种需求用 CLI 处理就是找到MSTextLayer节点的attributedString.string替换字符串再还原。不过改文字长度后文本框不会自动重算宽度如果原来固定了框宽新文字可能显示不全或被截断。改之前最好先查一下该图层是否设置了自动高度或者改完在 Sketch 里手动确认。另外要重点检查do_objectID。这些 ID 分布在document.json的图层节点、meta.json的样式引用、user.json的选中状态里。如果你用脚本修改 JSON 时不小心全局替换了某个 ID导致多处引用失配Sketch 打开后会显示“找不到对象”或直接崩溃。我做过一次教训是替换文本时顺手把do_objectID一起替换成了 UUID 新值结果页面之间的跳转关系全部断掉。执行还原后我几乎固定会跑一遍验证脚本确认还原后的文件能通过最基本的完整性检查import zipfile with zipfile.ZipFile(restored.sketch, r) as zf: names zf.namelist() required [document.json, meta.json, user.json] for f in required: if f not in names: raise SystemExit(f缺少必要文件: {f}) img_count len([n for n in names if n.startswith(images/)]) print(文件结构正常图片资源数:, img_count)这段代码用zipfile打开还原后的 sketch 文件检查三个必要 JSON 文件是否存在并统计图片资源数量。如果你转出的 JSON 里图层引用了图片但images/目录为空这里就能提前发现不用等设计师反馈“图裂了”。5. 那些让转换失败的坑排查与避坑记录5.1 现象还原后用 Sketch 打开直接报“文档已损坏”这个是最早遇到的翻车现场原因通常不是 JSON 格式不对而是整个 zip 包的结构不完整。Sketch 对 zip 包内部的文件顺序和某些隐藏字段有要求直接用 mac 上“压缩”功能打出来的 zip 包往往会多出__MACOSX隐藏目录Sketch 读这种包就容易报错。解决方法是不要用系统图形界面压缩而是用命令行zip -r压缩并在压缩前确认没有多余文件。CLI 里的restore命令一般会自动过滤这类污染文件但如果你是自己写脚本还原务必先做一次“还原后直接 zip 校验”。我习惯把校验加进 CI 流程里只要还原产物不能通过zipfile读取并找到三个关键 JSON就直接 fail 掉。5.2 现象还原后所有图片都变灰色占位块图片丢失几乎是每个用过 JSON 转 Sketch 的人必踩的坑。原因有两种一是转换时跳过了images/目录导出二是 JSON 里图片引用是绝对路径或外部链接根本没有打包进 zip。解决方法是转换时就明确不要跳过资源必要时把--skip-resources参数去掉。如果 JSON 里images/的引用是外部路径需要手工把这些图片也复制进输出目录或者把路径改成相对路径。图片资源的问题没有后悔药丢弃前一定要检查document.json里是否有image类型的引用字段。还有一个细节Sketch 的位图图层会有一个image字段指向images/目录下的文件名这个文件名的 hash 值必须与 JSON 里一致。如果你替换了图片文件但没改引用名Sketch 打开后会用旧缓存。5.3 现象多个设计师改了同一份 JSON合并时冲突炸了既然转 JSON 是为了版本管理那多人协作就绕不开“json merge conflict”。JSON 文件的结构让 git 的自动合并几乎不可用p andles数组里每个页面对象很长两个分支各自改了不同页面git diff 的冲突块却是整段整段地标红无法自动合并。如果你真的需要多人并行改 JSON我建议先把页面拆分到独立文件这样 git 至少能在文件级别处理冲突。合并时再用脚本按do_objectID做映射归并而不是让 git 硬合。这是我走过的弯路一度让两个设计师直接在一个巨型document.json改结果每次 merge 都要花一小时手工解决冲突最后还是回到按页拆分的老路。5.4 现象文本改完后文字溢出或消失前面提到改attributedString.string后文本框大小不会自动调整。这个问题的严重性远超想象——尤其是中英文混排时中文字符变多后自动换行逻辑可能失去作用画板打开后文字被截断。解决方法是修改前先定位该层级的style.textStyle段落样式看是否有自动行高或自适应设置。实在不行改完还原后打开 Sketch 人工过一遍。这不是技术问题是工作流的必要步骤。我在 CI 里加了“文本长度校验”每个MSTextLayer的字符串长度超出画板宽度的直接打印警告通知设计师复核。5.5 现象转换后 JSON 体积爆炸、提交到 git 后仓库变大几十倍JSON 的可读性是以体积为代价的。格式化 带分页拆分的 JSON 目录体积往往比原.sketch文件大 5 倍以上。图片资源本来就在 zip 里但如果你把images/目录也放进 git仓库会迅速膨胀到无法接受。解决方法是区分“数据”和“资源”。document.json、meta.json、user.json这三个文件值得入库因为它们承载了可 diff 的设计数据images/和previews/应该走资源管理方案或者干脆不入库需要时再整体导出。这个决策应该在项目启动时定好不然后面改会造成仓库历史无法清理。6. 进阶在 CI 里用 JSON 做版本对比和自动更新最后聊一个我目前每天都在用的落地技巧把 sketch-json-cli 转换出来的 JSON 放进 CI配合自动脚本做设计稿变更提示。这里有一个可以抄作业的实践。在 CI 里用git diff对比两次提交的document.json配合sketch-json-cli转换出的页面拆分文件可以实现“昨天和今天的设计稿到底改了什么”。我的做法是写一个小脚本检测到document.json有变更时加载新旧两份 JSON递归对比每个图层的name和关键属性输出一段可读的变更摘要#!/bin/bash # 提取当前版本的 JSON sketch-json-cli convert current.sketch --output ./current_json --pretty # 与上一次构建产出的 JSON 对比 diff -r ./previous_json/document.json ./current_json/document.json | head -n 80这段命令天然适用于 CI直接用diff -r比对整个 JSON 目录就能定位变化不用写复杂的 API。配合前文的 Python 遍历脚本可以进一步筛选出「图层名以btn_开头」的节点重点关注它的文本和样式变化。我还会加一步把变更摘要写入构建产物让设计师在 MR 描述里看到自动生成的“UI 变更说明”省掉了人工沟通成本。如果再往前走一步是 JSON 转 Sketch 的自动化修稿。比如批量替换字体颜色import json with open(document.json, r, encodingutf-8) as f: doc json.load(f) def replace_color(layers, old_hex, new_hex): for layer in layers: style layer.get(style, {}) fills style.get(fills, []) for fill in fills: color fill.get(color, {}) if color.get(red) old_hex[0]: color[red] new_hex[0] replace_color(layer.get(layers, []), old_hex, new_hex) replace_color(doc[pages][0][layers], (0.5, 0.5, 0.5), (1.0, 0.2, 0.2)) with open(document.json, w, encodingutf-8) as f: json.dump(doc, f, ensure_asciiFalse, indent2)这段代码递归遍历图层找到style.fills里的color字段做替换。注意color里的red、green、blue用的是 0 到 1 的浮点数不是 0 到 255 的整数这个转换经常让第一次写脚本的人翻车。改完后再跑一次sketch-json-cli restore就能得到一个颜色已更新的新设计稿。验证环节我从不省。还原后的文件先跑一次 zip 完整性校验再用 Sketch 打开确认改动生效。我在一个项目里用这套流程把设计稿版本对比时间从半小时减到两分钟真正解决了“改没改、改了哪”的疑问。希望这套思路帮你也省下那些被无效沟通消耗的时间——但记住任何自动化改造都要先做好完整备份毕竟设计稿没了比脚本报错可怕得多。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑