简介:这份资源是面向 Sketch 插件开发者与前端工程师的实验性项目,核心功能是把 JSON 文件转换为 Sketch 可识别的设计文件,适合需要批量生成图层、做设计数据驱动或研究 Sketch 插件机制的中高级开发者参考。压缩包共 9 个文件,约 81KB,以 json 配置与示例数据、js 插件命令脚本为主,另含 md 说明文档、png 图标及 lock 依赖锁定文件,结构精简,便于快速理解插件入口与 JSON 结构约定。项目基于 skpm 搭建,提供 build、watch、start 等 npm 脚本,并涉及 Babel 自定义配置,读者可据此掌握插件构建、调试与打包流程。已有 672 人学习,适合作为 JSON 转 Sketch 方向的入门样例与二次开发起点。
1. 从一份 JSON 到可编辑的 Sketch 文件:先把环境账算清楚
上周帮一个做设计系统的朋友救火,他手里有几百份从后端导出的 JSON 设计令牌,想批量转成 Sketch 文件交给设计团队改。他第一反应是找在线转换工具,结果文件传上去格式全乱,图层堆成一坨,字体样式全丢。后来他找到 json-sketchapp 这个 Sketch 插件,思路是对的——把 JSON 结构映射成 Sketch 图层,但装的时候卡在 skpm 构建这一步,报错信息看得他一头雾水。这类「JSON 转 Sketch」的需求在组件库迁移、设计令牌落地、跨工具同步里特别常见,装不好就是白折腾。这篇记录的是我实际跑通的一套环境,从 Node 版本、skpm 脚手架到插件加载验证,新手照着走能通,熟手能看到版本取舍和几个容易翻车的点。
2. 装前准备:Node、Sketch 与 skpm 的版本对位
2.1 为什么版本对位比装什么更重要
json-sketchapp 本质是一个 Sketch 插件,而 Sketch 插件的开发与打包依赖 skpm(Sketch Plugin Manager)这套工具链。skpm 又跑在 Node 上,所以真正决定你能不能跑通的,不是「装没装」,而是「三者版本对不对得上」。我见过最常见的翻车是:Node 装了最新的 20.x,skpm 用 npm 全局装了个老版本,结果skpm build直接抛Cannot find module 'sketch/dom',看起来像缺依赖,实际是 skpm 版本和 Sketch 的插件 API 不匹配。
常见做法是把 Node 锁在 16.x 或 18.x 的 LTS 线上。Node 20 不是不能用,但 skpm 的部分依赖在 20 上会有原生模块编译告警,尤其是涉及sharp或文件监听的包。我一般会直接用 nvm 切版本,避免全局污染:
# 安装并切换到 Node 18 LTS,json-sketchapp 的构建链在这个版本上最稳 nvm install 18 nvm use 18 node -v # 确认输出 v18.x.x npm -v # 确认 npm 版本在 9.x 左右这段命令的逻辑很简单:nvm install 18拉取 18 线最新 LTS,nvm use 18把当前 shell 切过去,后面两行是自检。参数上没什么可调的,关键是别跳过node -v这一步——很多人切了版本但终端没生效,后面所有报错都建立在这个错误前提上。
Sketch 这边,插件 API 在 Sketch 70 之后有过一轮调整,json-sketchapp 这类依赖sketch/dom的插件,建议 Sketch 版本不低于 72。如果你还在用 60 多的老版本,插件能装上但运行时拿不到Document对象,表现就是「菜单点了没反应」。这个坑后面排查章节还会细说。
2.2 环境清单与依赖对照
把要装的东西列成一张表,装之前对着勾一遍,比装到一半回头补要省事得多。下面这张表是我自己机器上验证过的组合,不是唯一解,但属于「照着装大概率不出事」的那一档:
| 组件 | 推荐版本 | 作用 | 装错的表现 |
|---|---|---|---|
| Node.js | 18.x LTS | 运行 skpm 与构建脚本 | 原生模块编译失败、监听失效 |
| npm | 9.x | 拉取依赖 | 依赖树解析异常 |
| skpm | 1.1.x | 插件脚手架与打包 | build 报找不到 sketch/dom |
| Sketch | 72 及以上 | 宿主应用 | 插件菜单无响应 |
| json-sketchapp | 按仓库当前主分支 | JSON 转图层逻辑 | 图层结构错乱 |
skpm 的安装我倾向全局装一份,方便在任意目录初始化:
# 全局安装 skpm,锁定 1.1 线,避免拉到不兼容的大版本 npm install -g @skpm/cli@1.1 skpm --version # 输出版本号即安装成功@skpm/cli是包名,@1.1是版本范围约束,不加的话 npm 会拉 latest,而 latest 在部分环境下会引入与老插件模板不兼容的配置项。skpm --version是验证命令,输出正常版本号说明全局 bin 路径已进 PATH;如果提示 command not found,多半是 npm 全局前缀没配好,用npm config get prefix看一眼,把对应 bin 目录加进 PATH 即可。
2.3 拉取项目与目录结构确认
拿到 json-sketchapp 的源码后,先别急着npm install,花三十秒看一眼目录结构。这类插件项目通常有src/(插件逻辑)、resources/(图标与静态资源)、package.json(skpm 配置入口)。package.json里的skpm字段决定了 manifest 怎么生成,如果这个字段缺失或写错,后面skpm build出来的.sketchplugin是空壳。
# 进入项目目录后先看结构,确认 package.json 里存在 skpm 配置段 cd json-sketchapp ls -la cat package.json | grep -A 10 '"skpm"'ls -la看隐藏文件,有些项目把.skpmrc放在根目录;grep -A 10 '"skpm"'把配置段连同后面十行一起打出来,方便确认manifest、handler这些关键字段在不在。如果这条 grep 没有任何输出,说明项目用的是旧版模板,需要手动补 skpm 配置,否则构建阶段会直接失败。
3. 安装与构建:从依赖到 .sketchplugin
3.1 依赖安装:别让 lock 文件骗了你
进入项目目录后的第一步是装依赖。这里有个血泪经验:如果仓库里带了package-lock.json,优先用npm ci而不是npm install。npm ci会严格按 lock 文件还原依赖树,不会因为某个包的 minor 版本更新而引入行为差异;npm install则可能悄悄升级间接依赖,导致「昨天能 build 今天不行」的玄学问题。
# 有 lock 文件时用 ci,保证依赖树与作者环境一致 npm ci # 没有 lock 文件时才用 install,并观察是否有 peer dependency 告警 npm installnpm ci的前提是 lock 文件存在且与 package.json 同步,不同步会直接报错退出——这其实是好事,等于帮你提前发现依赖声明不一致。npm install之后要留意输出里的ERESOLVE或peer dep告警,json-sketchapp 依赖的sketch类型包对 peer 版本有要求,告警不处理的话,构建时类型解析会出问题。装完用npm ls --depth=0扫一眼顶层依赖,确认没有UNMET标记。
3.2 skpm 构建:manifest 与入口的对应关系
依赖装好后就是构建。skpm 的构建命令会把src/下的入口文件打包,并根据package.json的 skpm 配置生成manifest.json,最终产出.sketchplugin目录。这一步最容易出的问题是入口路径对不上:package.json里写的handler是src/index.js,但实际文件叫src/main.js,构建不报错,装进 Sketch 后菜单点了没反应。
# 执行构建,产出 .sketchplugin skpm build # 构建完成后确认产物存在,并检查 manifest 内容 ls -la *.sketchplugin cat *.sketchplugin/Contents/Sketch/manifest.jsonskpm build默认走生产模式,产物会做压缩;调试阶段可以用skpm build --watch,改源码自动重建,省得反复手动跑。构建成功后当前目录会出现一个以项目名命名的.sketchplugin包,ls那行就是确认它真的生成了。cat manifest.json是关键的验证动作——重点看commands数组里的script字段是否指向真实存在的 JS 文件,以及handlers里的run是否和源码导出的函数名一致。这两处任何一处对不上,插件都会「装得上、跑不动」。
3.3 安装到 Sketch:两种方式与各自的坑
产物有了,接下来是让 Sketch 认它。常见两种方式:一是双击.sketchplugin让 Sketch 自动安装,二是手动软链到插件目录。双击安装简单,但每次重新构建都要重新双击,调试效率低;软链方式改完源码重建后 Sketch 重启即可生效,适合反复迭代。
# 方式二:软链到 Sketch 插件目录,macOS 下的典型路径 ln -s "$(pwd)/json-sketchapp.sketchplugin" \ ~/Library/Application\ Support/com.bohemiancoding.sketch3/Plugins/json-sketchapp.sketchpluginln -s的第一个参数是源(当前目录下的产物),第二个是目标路径。注意路径里有空格,必须用反斜杠转义或整体加引号,否则 shell 会把路径拆成两段,软链建到一个不存在的目录里。建完软链后完全退出 Sketch 再重开(不是关窗口,是 Cmd+Q),插件菜单里才会出现对应条目。如果菜单里没有,先去Plugins菜单下的Manage Plugins看列表里有没有,没有就是软链路径写错了。
提示:Sketch 对插件目录的读取发生在启动时,任何插件文件的增删改都需要重启应用才生效,热更新在这套链路里不存在。
4. 配置与参数:让 JSON 映射按你的结构走
4.1 理解 JSON 到图层的映射规则
json-sketchapp 的核心逻辑是把 JSON 的节点树翻译成 Sketch 的图层树。它通常约定一套字段名,比如type决定图层类型(矩形、文本、组),frame决定位置尺寸,style决定填充与描边。装完插件只是第一步,真正决定输出质量的,是这份 JSON 的字段结构是否和插件的解析逻辑对齐。
我一般会先拿一份最小 JSON 做验证,而不是直接上几百个节点的真实数据。最小样例只保留三层:一个根组、一个矩形、一个文本。跑通之后再逐步加字段,这样出问题时能快速定位是哪个字段没被识别。
{ "type": "group", "name": "root", "children": [ { "type": "rectangle", "name": "bg", "frame": { "x": 0, "y": 0, "width": 200, "height": 100 }, "style": { "fills": [{ "color": "#FFFFFF" }] } }, { "type": "text", "name": "label", "frame": { "x": 16, "y": 16, "width": 160, "height": 24 }, "text": "Hello" } ] }这份样例里,type是分发键,插件根据它决定走哪个构造分支;frame的四个字段缺一不可,缺width或height时部分版本会退化成默认尺寸,图层叠在一起看起来像「没生成」;style.fills里的颜色值格式要和插件解析器约定的一致,十六进制带不带#、大小写,都可能影响解析结果。先用这份跑,确认 Sketch 里出现一个白底矩形加一行文字,再换真实数据。
4.2 插件参数与运行入口的调整
有些版本的 json-sketchapp 会在插件运行时弹出一个文件选择框,让你选 JSON 文件;也有版本走「读取固定路径」的逻辑。这两种行为由入口脚本里的参数决定,装完后值得打开源码确认一下,免得点了菜单不知道文件从哪来。
// 入口脚本中常见的文件读取逻辑,路径与编码是两个关键参数 const fs = require('sketch/fs'); const jsonPath = '/Users/yourname/Desktop/design-tokens.json'; // 读取时显式指定 utf8,避免中文图层名变成乱码 const raw = fs.readFileSync(jsonPath, 'utf8'); const tree = JSON.parse(raw);readFileSync的第二个参数'utf8'不能省,省了拿到的是 Buffer,JSON.parse会直接抛错;jsonPath建议改成绝对路径,相对路径在不同启动方式下解析基准不一样,容易读不到文件。如果你的 JSON 里有中文图层名,编码问题会表现为 Sketch 里图层名全是问号或方块,这时候回头检查这一行基本能定位。改完源码记得重新skpm build并重启 Sketch,软链方式下这一步不能跳。
4.3 批量转换时的结构约定
真实场景里很少只转一个文件,设计令牌往往是几十上百份 JSON。批量跑的时候,我一般会在项目外再包一层脚本,遍历目录、逐个调用转换逻辑,而不是改插件源码去支持批量——插件保持单一职责,批处理放在外部,出问题好回滚。
# 批量遍历目录下的 JSON,逐个交给转换脚本处理 for f in ./tokens/*.json; do node ./scripts/convert.js "$f" || echo "failed: $f" donefor f in遍历通配符匹配到的文件,"$f"加引号防止文件名带空格被拆开,|| echo让单个文件失败不中断整批,同时留下失败记录。这个模式的好处是失败可追溯,坏处是没有并发,文件多的时候慢;要提速可以换xargs -P,但并发写 Sketch 文档本身有风险,我倾向保守串行。批量转换前务必确认每份 JSON 的根节点类型一致,根是group和根是rectangle混在一起时,输出结构会参差不齐。
5. 避坑与排查:五条真实踩过的记录
5.1 插件菜单出现但点击无响应
现象:Sketch 的 Plugins 菜单里能看到 json-sketchapp,点下去没有任何窗口弹出,也没有报错提示。
原因:manifest 里的script指向的 JS 文件不存在,或者入口函数名与handlers.run不匹配。构建阶段不校验这个对应关系,所以 build 是「成功」的。
解决:打开.sketchplugin/Contents/Sketch/manifest.json,核对commands[].script的文件名,再去对应目录确认文件真实存在;然后看源码里export default function或module.exports导出的名字,和 manifest 的handlers.run对齐。改完重建、重启 Sketch。
5.2 构建报 Cannot find module 'sketch/dom'
现象:skpm build中途退出,报找不到sketch/dom或sketch/fs。
原因:skpm 版本过老,没有内置 Sketch 运行时模块的类型声明与桩实现;或者 Node 版本过高导致依赖解析路径变化。
解决:先skpm --version确认在 1.1 线,低于这个版本就重装;再node -v确认在 18.x。两个都对还报错,删掉node_modules和 lock 文件重装一遍,排除依赖树污染。
5.3 生成的图层全部堆在原点
现象:转换成功,但所有图层坐标都是 (0,0),叠在一起像只有一个图层。
原因:JSON 里的frame字段名写成了rect或bounds,插件解析器认不出,回退到默认值。
解决:对照插件源码里的字段读取逻辑,确认它读的是frame.x/y/width/height还是别的命名。字段名以源码为准,不以你的直觉为准。改 JSON 比改插件源码安全。
5.4 中文图层名变成乱码
现象:Sketch 里图层名显示为问号或方块。
原因:读文件时没指定utf8编码,或者 JSON 文件本身不是 UTF-8 保存的。
解决:源码里readFileSync补上'utf8';同时用编辑器确认 JSON 文件编码,带 BOM 的文件也可能出问题,存成无 BOM 的 UTF-8。
5.5 重启 Sketch 后插件消失
现象:第一次装完能用,重启 Sketch 后菜单里没了。
原因:用的是双击安装,Sketch 把插件复制到了自己的目录,但后续重新构建覆盖了源产物,两边不同步;或者软链指向的源目录被移动、重命名。
解决:统一走软链方式,源目录固定不动;每次重建后只重启 Sketch,不重复双击安装。软链断了用ls -l看目标路径是否还有效,失效就删了重建。
6. 装完怎么验证:三层自检让转换结果可信
装完不等于跑通,跑通不等于结果对。我习惯用三层自检收尾,从「插件活着」到「数据对得上」,每层都有明确的通过标准,任何一层不过就停在那一层排查,不往下走。
第一层是插件层自检。重启 Sketch 后打开 Plugins 菜单,确认 json-sketchapp 条目存在且可点击;点一次,观察是否有文件选择框或控制台输出。Sketch 的插件日志在Plugins菜单下的Run Plugin附近能调出,或者看 macOS 控制台的Sketch进程输出。这一层只验证「入口通了」,不关心转换结果。
第二层是单文件转换自检。用 4.1 节那份最小 JSON 跑一次,通过标准是:Sketch 里出现一个名为 root 的组,组内一个 200×100 的白色矩形和一个文本图层,文本内容为 Hello,位置分别在 (0,0) 和 (16,16)。任何一项不符,回到第 4 章对字段。这一层验证的是「映射逻辑对」。
第三层是真实数据抽样自检。从批量结果里随机抽三份,和原始 JSON 逐节点比对图层数量、名称、尺寸。我一般会写个极简的核对脚本,把 Sketch 文档导出成 JSON 再和源数据做 diff:
# 抽样核对:统计源 JSON 与导出结果的节点数是否一致 node -e " const src = require('./tokens/sample.json'); const out = require('./export/sample.json'); const count = (n) => 1 + (n.children || []).reduce((s, c) => s + count(c), 0); console.log('source nodes:', count(src)); console.log('output nodes:', count(out)); "这段脚本用递归数节点,count函数对每个节点算 1 再加上子节点递归结果,reduce做累加。两个数字相等不代表结构完全一致,但数字不等一定有问题,是最低成本的冒烟检查。抽样三份都过,基本可以认为这批转换可信;有一份不过,就把范围缩到那份 JSON 的字段结构上查。
三层走完,这套环境才算真正落地。从那以后我每次装这类「格式转换型」插件,都强制先跑最小样例再上真实数据,绝不跳过单文件验证直接批量——省下的那十分钟,往往要用一晚上排查来还。希望帮到你。
本文还有配套的精品资源,点击获取