简介:sketch-json-cli 是一款面向设计师、前端开发者和设计协作团队的命令行工具,核心功能是在 Sketch 文件与 JSON 数据之间进行双向转换。它能够将 .sketch 源文件解析为结构化 JSON,便于把设计稿纳入 Git 等版本控制系统,从而实现变更差异对比、多人协同评审和脚本化处理;同时也能把修改后的 JSON 数据重新封装为 Sketch 文件,适合批量替换文本、调整图层参数或在持续集成流水线中动态生成设计资产。该资源包共包含 8 个文件,压缩后体积仅 34KB,核心为 index.js 脚本,配有 package.json 与 yarn.lock 依赖锁定、readme.md 使用说明、.travis.yml 持续集成配置、license 许可证和 .gitignore 文件,精简而完整。目前已有 389 人学习或下载。对于想了解 Node.js CLI 设计的开发者,这是一份轻量的源码范例;对于设计团队,可直接安装该工具嵌入现有工作流,亦可基于源码二次开发,扩展更多格式支持。 做设计稿自动化处理的时候,最让人头疼的往往不是设计本身,而是文件格式的黑盒。Sketch 的.sketch文件平时在编辑器里用着顺手,可真到了团队协作、代码评审、批量修改阶段,这玩意儿就像个只进不出的保险箱。sketch-json-cli 就是为解决这个问题而生的。它做的事情非常纯粹:把.sketch文件解包成可读、可改、可 diff 的 JSON,也能把处理后的 JSON 重新打包回.sketch文件。无论你是设计师想看清楚设计稿里到底存了什么,还是前端想把设计稿接进 CI 流程做自动化校验,这工具都能派上用场。这篇文章我会从底层文件结构讲起,把解包、修改、回包全流程跑一遍,再把实际操作中踩过的坑一并交代清楚。
1. 项目概述与核心价值
1.1 设计稿为什么需要 JSON 化
先别急着装工具,想清楚一个问题:为什么非要把设计稿转成 JSON?直接打开 Sketch 编辑不就好了?
实际工作流里,设计稿文件常年在几个环节之间流转。前端要量尺寸、切图、核对标注,设计要维护组件和样式规范,还有版本管理、多人协作、自动化测试这些场景。.sketch文件在这些场景里的表现相当糟糕。它是压缩过的二进制格式,git 里能存,但每次变更产生的 diff 完全不可读——一坨乱码,除了告诉你"文件变了"之外,什么都看不出来。代码评审的时候设计师改了某个按钮的圆角,前端在 PR 里盯着那几百行二进制差异,根本无从判断具体改了哪。
JSON 就不存在这个问题。它是纯文本,能进 diff,能写脚本遍历,能被 CI 工具解析,甚至能接进翻译平台做文案同步。设计稿一旦 JSON 化,就从"只能给人看的图片"变成了"能被机器处理的数据"。
1.2 sketch-json-cli 的具体定位
sketch-json-cli 做的事情是双向转换:.sketch文件转成 JSON,JSON 转回.sketch文件。它用 Node.js 开发,通过命令行调用,不要求你懂 Sketch 的底层格式,也不要求会写插件。
实际使用中它的定位是"设计稿数据交换层"。上游是设计师产出的.sketch文件,下游是你的脚本、代码仓库、自动化流程。你在中间加一层 JSON 转换,就能把设计稿数据接进任何你想接的系统里。这比让设计师在 Sketch 里手动导出、手动整理要靠谱得多,也比写一个完整的 Sketch 插件门槛低得多。
2. 工具选型与方案解析
2.1 Sketch 文件底层是 Zip 压缩包
要理解 sketch-json-cli 的工作原理,先得知道.sketch文件到底是什么。它本质上是一个 Zip 压缩包,里面放着若干文件和目录。早期版本的 Sketch 文件结构还比较直白,有个document.json存全局数据,有个pages目录放所有页面数据,还有previews目录放缩略图,images目录放图片资源。
后来 Sketch 版本迭代,文件结构做了调整,pages目录里不再存放完整页面 JSON,而是变成引用关系。核心数据集中在document.json里,页面内容通过引用 ID 关联到各个 page JSON 文件。但万变不离其宗:只要是.sketch文件,扒开外壳就是一堆 JSON 加资源文件的组合。
sketch-json-cli 的工作就是把这个 Zip 包解开,把内部的 JSON 文件整合成一个(或一组)可读的 JSON 输出给你。反向操作时,它再把你提供的 JSON 数据组装回 Sketch 能识别的目录结构,最后压缩成.sketch文件。
2.2 为什么选 sketch-json-cli 而不是写脚本硬解
理论上你自己用 Python 或者 Shell 脚本也能实现解包逻辑:unzip、读 JSON、再 zip 回去。但实际做一遍就会发现坑比想象的多。
Sketch 的 Zip 包结构并不是普通压缩文件那么简单。图层样式、渐变、阴影、布尔运算这些数据,在 JSON 里有着特定的 schema,字段名、层级结构、必填项都有讲究。如果你只是把 Zip 解开改了某个字段再压回去,大概率会得到损坏的文件——Sketch 打开时会直接报错或者丢失图层。
Sketch 官方其实提供过命令行工具sketchtool,能导出切片、能导出 JSON,但它是单向的,不支持把 JSON 重新打包回.sketch文件。而社区里像sketch-json-cli这样的工具,实现了完整的双向转换,同时处理了 schema 兼容问题。这比我全手写、自己维护一套类型定义省太多事了。
2.3 工具的局限也要心里有数
坦诚讲,sketch-json-cli 不是万能的。它主要面向基于传统 Sketch 文件格式的版本。新版 Sketch 推出了一些新的文件特性(比如云文档、组件库关联),这些在转换时可能丢失关联信息。另外,文档里对图片资源的处理也比较基础——解包出来是 base64 还是独立文件,不同版本行为不一样。这些都是使用前需要知道的心理预期,省得踩了坑再抱怨工具不行。
3. 核心细节解析与实操要点
3.1 解包:从 .sketch 到 JSON
sketch-json-cli 的解包命令核心流程是:打开 Zip 包、读取全部 JSON 文件、按规则合并、输出。
以典型用法为例,你执行:
sketch-json-cli extract design.sketch -o design.json工具内部会把document.json和各个pages/*.json全部读出来,按照do_objectID和引用关系拼接成一个完整的 JSON 树。输出结果里你能看到pages数组下的每个页面,每个页面下是layers树状结构——基本上跟 Sketch 的画布层级一一对应。
这里有个关键点:不同版本的 sketch-json-cli 输出结构不一定完全相同。有的版本解包后是"一整个 document 对象",有的版本会把 pages 单独拆分成多个 JSON 文件。你要是写自动化脚本处理解包结果,先打印一级结构看看再写逻辑,别想当然。
3.2 JSON 结构解剖
用编辑器打开解包后的 JSON,第一感觉是"这结构也太深了"。类似这种:
{ "pages": [ { "objectID": "ABC123", "type": "page", "name": "首页", "layers": [ { "objectID": "DEF456", "type": "artboard", "name": "手机端 V1", "frame": { "x": 0, "y": 0, "width": 375, "height": 812 }, "layers": [ { "objectID": "GHI789", "type": "text", "name": "标题", "style": { "fills": [...], "textStyle": { "encodedAttributes": { "MSAttributedStringFontAttribute": { "fontName": "PingFangSC-Semibold", "size": 24 } } } } } ] } ] } ] }看到这段结构,你应该马上意识到几件事。第一,图层的name字段非常关键,日常你想定位某个元素,基本都是靠它。第二,坐标尺寸在frame对象里,单位是像素。第三,样式信息藏在style对象里,文本样式在textStyle.encodedAttributes里,填充、边框、阴影分别在fills、borders、shadows数组里。这些命名虽然有点反直觉,但记住之后操作效率会高很多。
3.3 回包:从 JSON 到 .sketch
回包命令也一样直白:
sketch-json-cli apply design.json -o design-output.sketch它做的事情是把 JSON 数据重新组装成 Sketch 能识别的 Zip 包。这里有一个特别值得注意的细节:Sketch 对 Zip 包内的压缩算法有要求。普通压缩你随手用系统自带的"压缩"功能都能压,但 Sketch 打开时如果发现某些文件被压缩的方式不对,会直接报"文件已损坏"。
sketch-json-cli 内部对这个问题做了处理,它会用正确的压缩参数来重新打包,这也是我不推荐你用 numpy 拆 ZIP 再手动 zipfile 打包的根本原因——细节太多,自己扛不如让工具扛。
回包后强烈建议先双击打开检查一下,确认图层没丢、样式没乱、能正常编辑。工具本身能保证 schema 合法,但你的 JSON 修改逻辑可能引入业务层面错误,机器检测不出来。
4. 实操过程与核心环节实现
4.1 环境准备与安装
sketch-json-cli 是 Node.js 生态的工具,装之前确保本机有 Node.js 环境,建议用 LTS 版本。
npm install -g sketch-json-cli全局装完就能用了。如果公司有私有 npm 仓库,也可以装到项目依赖里配合 npx 使用,这样版本好锁、团队好统一。我实际用下来觉得全局装比较顺手,因为经常在不同项目里随意转换文件,不用每次都 cd 到固定目录再执行 npx。
4.2 最基础的命令实操
打开终端,找个.sketch文件试一下:
sketch-json-cli extract sample.sketch -o sample.json输出文件生成后,用 VS Code 或者任何支持 JSON 格式化的编辑器打开。初次接触的话建议先用格式化功能让层级清晰一点,再一级一级展开看结构。这时候你会对"设计稿里到底存了什么"产生最直观的理解——原来所有图层的名字、坐标、大小、字体、颜色,全都清清楚楚地列在这里。
反向转换的命令注意文件名别写反了:
sketch-json-cli apply sample.json -o sample-copy.sketch如果一切正常,应该会生成一个新的.sketch文件,用 Sketch 打开它,内容跟原文件一致或者只有你修改过的地方有差异。
4.3 实战:批量修改所有图层文字内容
单看文件结构不解决实际问题,来一个实际场景。假设设计稿里有一批文本图层,文案要统一加上版本号后缀,比如"立即购买"要变成"立即购买 V2"。手动改费劲,用脚本处理就简单了。
先写一个 Node.js 脚本处理解包后的 JSON:
const fs = require('fs') const data = JSON.parse(fs.readFileSync('sample.json', 'utf-8')) function walkLayers(layers) { if (!Array.isArray(layers)) return layers.forEach((layer) => { if (layer.type === 'text' && layer.attributedString) { const base = layer.attributedString.string if (base && !base.includes('V2')) { layer.attributedString.string = `${base} V2` } } if (layer.layers) { walkLayers(layer.layers) } }) } data.pages.forEach((page) => walkLayers(page.layers)) fs.writeFileSync('sample-modified.json', JSON.stringify(data, null, 2))这里要注意attributedString.string是文本图层真正的文字内容,不要改到name字段,那是图层名,不是显示的文案。脚本写法上递归遍历layers树,因为在 Sketch 数据结构里,页面里是画板,画板里是图层,图层里还可能有编组,只有递归才能不漏。
执行完脚本再回包:
sketch-json-cli apply sample-modified.json -o sample-v2.sketch打开文件就能看到所有文本图层的文案都已经更新了。整个过程不到一分钟,手动改的话几十个图层得折腾半天。这就是把设计稿数据化之后最直接的红利。
4.4 更进一步:接入 git 做设计稿版本管理
如果你所在团队对设计稿版本管理要求高,每次都靠设计师手动导出不同版本,那可以更进一步:把 sketch-json-cli 解包出来的 JSON 直接提交到 git 仓库。
这样每次设计稿变更,git diff 都能精确到某个图层改了什么。比如:
- "name": "按钮-主色", + "name": "按钮-主色-禁用态",或者字号从 14 改成 16,git diff 里都能看得到。这比任何设计稿管理工具的"历史记录"都好使,因为这里是代码仓库,有分支、有 review、有 blame,跟代码的协作方式完全一致。
实践中比较常用的流程是:在项目仓库里放一个design/目录,设计师更新设计稿后执行一次 extract,把 JSON 和.sketch文件一起提交。前端在开发新功能时,pull 最新代码看设计稿 diff,就知道这次设计变更了哪些位置,心里有数。
5. 常见问题与排查技巧实录
5.1 Sketch 新版本文件打不开或报 schema 错误
这个是社区里被问得最多的问题。Sketch 每个大版本升级,文件内部的 schema 都有可能调整。你拿旧版 sketch-json-cli 解包新版 Sketch 文件,可能解包后 JSON 结构对不上,回包后文件打开就报错。
解决方案依次尝试:先升级 sketch-json-cli 到最新版本;如果还不行,看输出报错信息里提示的是哪个 schema 字段,手动在 JSON 里补全或删掉;最后一招是在旧版 Sketch 里打开设计稿,另存为旧格式再转换。实际处理中大部分问题是升级工具版本就能解决的,项目组里最好关注一下工具的 release 信息,别常年停在老版本。
5.2 回包后文件里的预览图和缩略图丢了
在 Sketch 里打开文件的时候,有些版本会从previews目录读取缩略图用于显示。如果你处理的 JSON 是从工具解包来的完整结构,重新打包时预览信息通常还在。但如果你只保留了一部分 JSON 文件,或者手动改了文件结构,缩略图可能会丢,Sketch 打开时会显示空白或者重新生成预览。
这个不影响编辑,但如果你用 Finder 的"快速查看"功能看缩略图,可能显示不出来。解决办法是重新在 Sketch 里保存一次文件,预览信息会重新生成。小问题,但遇上了别慌。
5.3 字体和排版在转换后出现偏移
JSON 里文本图层的fontName和size都是精确记录的。但如果你换了一台电脑打开文件,这台电脑上没有安装对应字体,Sketch 会做字体替换,排版自然就变了。这不是工具的问题,是字体环境的问题。
通过 JSON 去排查这类问题效率反而更高。你可以在解包后的 JSON 里全局搜索fontName,看用了多少种不同的字体,一眼就能发现设计稿里有没有用落伍的、容易缺失的第三方字体。检查一遍哪些字体没装,批量替换掉,回包再打开,问题就解决了。
5.4 JSON 文件太大,编辑器卡顿
设计稿如果页面多、图层量大,解包后的 JSON 可能几十 MB 甚至上百 MB。编辑器打开卡顿是常有的事。这里分享几个实操经验。
优先用 VS Code 处理,配好大文件支持参数后会好很多。终端里用jq做查询切片:
jq '.pages[0].layers[0]' sample.json这样不需要一次性加载整个文件,就能快速查看某一部分的结构。修改的时候也建议用 Node.js 脚本做精确操作,别在整个大文件里手动滚动着改,容易出错。
5.5 字符编码问题导致文案乱码
中文文案在 JSON 里通常以 UTF-8 编码存储,正常情况不会乱码。但我遇到过 Windows 环境下用默认编码写 JSON 然后回包,Sketch 里打开中文全部变成乱码的情况。
解决方法是写脚本时强制指定 UTF-8 编码读写文件,不要依赖系统默认值。Node.js 里用fs.writeFileSync(path, data, 'utf-8'),Python 里用open(path, 'w', encoding='utf-8'),能避免绝大多数编码坑。
6. 自动化工作流里的进一步玩法
6.1 将设计稿检查接入 CI
既然设计稿已经是 JSON 了,自然能跟 CI 流程打通。可以写一条检查规则:解析 JSON,找出所有名为"按钮"的图层,检查它们的frame.width是否一致。不一致就报错,让设计师修正后再合并。这种检查在纯手工流程里想都不敢想,但有了 JSON 中间层后实现成本非常低。
我见过一个团队的做法是把解包后的 JSON 作为 golden reference 放到仓库里,前端每次改动前先比较一次,一旦设计稿有变化但样式代码没跟上,CI 就会提示。这个过程完全自动化,发现问题的时机从"新功能发布后"提前到了"提 PR 时"。
6.2 用脚本做设计规范检测
设计规范是团队协作里相当重要的部分,字体、字号、颜色、间距这些基础规范如果能自动检测,能省下大量走查时间。下面是检查文字图层字体权限的简单实现:
const data = JSON.parse(fs.readFileSync('sample.json', 'utf-8')) const fontSet = new Set() function walk(layers) { if (!Array.isArray(layers)) return layers.forEach((layer) => { if (layer.style && layer.style.textStyle) { const attrs = layer.style.textStyle.encodedAttributes if (attrs && attrs.MSAttributedStringFontAttribute) { const font = attrs.MSAttributedStringFontAttribute fontSet.add(`${font.fontName} ${font.size}`) } } if (layer.layers) walk(layer.layers) }) } data.pages.forEach((page) => walk(page.layers)) console.log([...fontSet].join('\n'))这个脚本跑完,所有文本图层用到的字体和字号一目了然,很容易发现哪种字体超出规范。
7. 需要注意的几个实操细节
整个流程跑下来,下面这几点是我认为决定成败的关键:
第一,永远保留原始文件备份。转换和修改操作都是对文件的改写,尤其是批量修改脚本,一旦逻辑有遗漏(比如误改了图层名而非文案),回包后设计稿可能千疮百孔。改之前先复制一份原文件,这是最基本的保险。
第二,解包后的 JSON 要按目录管理。如果团队多人参与修改,建议一个页面一个 JSON 文件,分开提交、分开 review,这样冲突会少很多。直接放一个大 JSON 在仓库里,就算 git 能处理,合并起来也很痛苦。
第三,操作要小步提交。改一个字段、回包、打开验证,再改下一个。不要攒了一堆修改再一次性回包,出了问题排查起来特别费劲。既然是命令行工具,完全可以配合脚本循环执行,改一部分验证一部分。
第四,关注工具的 issue 列表。sketch-json-cli 本身是社区工具,维护节奏不一定稳定,新版本 Sketch 发布后可以去 issue 看看有没有兼容性反馈。如果长时间没更新,备选方案是 fork 一份自己维护。
在我自己的项目里,这个工具已经成了设计稿数据处理的固定环节。每周设计稿更新后自动解包、同步到 git,前端和设计的协作不再靠飞来飞去的图片和口头描述,所有变更都变成可查看的代码差异。如果你也在处理设计稿和代码的对接问题,这套方案值得试试,先拿一个简单的页面跑通流程,再逐步铺开,你对设计稿的管理方式会完全变个样。
本文还有配套的精品资源,点击获取