很多公司在设计提效方面推出了各自的sketch插件来做sketch资源管理,方便设计师使用资源,我们也开发了自己的sketch插件- Astro (阿斯特罗) 来提升设计师侧的资源使用效率
Sketch插件提供了多种开发方式 , 包括OC, JS, 也有使用swift开发的。
sketch是oc开发,并且使用cocoaScript作为插件开发语言,实现了jsAPI, 我们也将采用CocoaScript和js的方式开发插件
插件「阿斯特罗」主要功能有管理业务分组及其对应的设计组件库,还有静态图片资源的使用,以及自动填充文本,图片的功能。
为了提高开发效率及以后的维护和迭代,该插件采用的是sketch侧封装api功能函数配合webview页面的开发方式。
这篇文章主要讲以下几点
- 开发所需依赖
- 插件实施方案
- 环境搭建问题处理
开发环境
Skpm
首先最主要的就是安装 skpm , skpm 是sketch提供的插件脚手架工具,并且其中提供了sketch的jsApi。
Http-server
这个主要是开发模式下访问本地图片资源的时候使用到
sketch-module-web-view
sketch插件的一个 webview npm包 ,提供了和electron类似的窗口管理功能
Vue3 全家桶 + antdv
页面内容技术栈,主要是要开发体验好一些
Sketch-dev-tools
一个用来调试sketch插件的开发者工具,可以看到打印信息, 还可以执行一个skpm包里的一些方法
,其他功能还是未开发的一个状态
Sketch developer
Sketch插件论坛还是不错的,很多人在里面说自己的问题和为别人解决问题,不过有的问题会受sketch版本的差错,所以需要甄别一下,开发的时候在里面找到了不少的解决方案。
项目结构
开发方式
由于我们需要一定的离线使用的能力,并且有较高的加载速度,所以最好采用加载本地 html 文件的方式。但如果开发模式下加载本地文件,则会失去 现在热更新的开发体验
所以最后采用了一种 dev 模式下,直接加载 vue 应用的服务, prod 模式下加载本地文件的思路. 但是这样会有一个问题 。就是 vue 默认是单页面应用, 当我们切换窗口时需要更换不同的页面,所以我们需要将项目修改为多页面打包的应用。 大概模式如下图
vue项目打包配置如下,需要注意下打包后的资源路径,之后要用
问题:
因为sketch-webview这个插件加载html后会将通过本身的webpack进行打包处理,之后会打包到下面这个目录中。
但是生产模式打包后的静态资源并不会自动导入到插件的包文件中,所以我这在打包的时候通过命令去将打包后的静态资源移动到插件包中所以修改了下开发和打包的命令,如下
"dev": "concurrently \"npm run watch\" \"cd src/webapp && npm run serve\"",
"build:prod": "cd src/webapp && npm run build && cd ../../ && mv -f ./src/webapp/dist/*.html ./src/webview/ && rm -rf ./astro.sketchplugin/Contents/Resources/_webpack_resources/* && NODE_ENV=production skpm-build && mv -f ./src/webapp/dist/static ./astro.sketchplugin/Contents/Resources/_webpack_resources/static",
命令比较长,可以通过一个脚本来做,偷懒了直接命令搞起来,不是很优雅,都是些常见命令
有一点需要注意下就是在开发过程中,我们首次需要在根路径下运行一下 skpm-link 命令, 将插件软链接到 sketch 的插件目录, 并加载到插件目录中
先来看一下完整的项目架构图
基本的开发环境就是这样啦 接着就是开发功能啦
再开发功能前,大概看了下sketch对于javascript环境的一个说明,看上去支持的是这样的
看到这个图 , 给人的感觉就是集成了一个精简的node环境,那岂不是为所欲为。捋起袖子加油干
webview 与 插件侧通信
通过向window挂在事件的方式注册提供给plugin侧调用的方法
注册方式
window.registerEvent('eventName', () ⇒ {
// plugin侧调用webview里的方法执行的函数
})
webview调用plugin侧的方式
window.callPlugin(eventName, data?, callback?);
// 有参数
window.callPlugin('eventName', { name:'zhangsan' }, (data) => {
console.log(data);
});
// 无参数
window.callPlugin('eventName', (data) => {
console.log(data);
});
// webview侧调用plugin里的方法方法
本来没有回调函数,因为 postMessage 就是支持方法名 和一个字符串类型的参数,但回调对交互后的逻辑是至关重要的,所以我们需要进行一点加工
export function callPlugin(eventName: string, data?: any, callback?: Function) {
callback = isFunction(data) ? data : callback;
data = isFunction(data) ? null : data;
const json: any = { data, callbackName: null };
if (callback) {
const callbackName = randomString(8); // 随机字母字符串
window[callbackName] = (res: any) => {
callback && callback(res);
delete window[callbackName];
};
json.callbackName = callbackName;
}
window.postMessage(eventName, json);
}
我们动态的去生成一个函数,并将其绑定到 window 上,再将函数名添加到数据中去,这样在插件侧我们可以获取绑定的函数名,处理完逻辑后回调该函数,执行后将挂载在 window 上的方法进行删除, 这样就实现了回调函数的功能。
Plugin侧
注册提供给webview端页面调用的方法
browserWindow.registerFun('eventName', () ⇒ {});
调用webview端函数的方法
browserWindow.callWebView('eventName', { name:'zhangsan' });
有了开发环境和通信方式,我们就可以开发我们的sketch插件了,但是在开发过程用到一些 polyfill 时, 发现了大问题,理想很丰满,现实很骨感,原来那些polyfill 是用cocoaScript调用oc实现的 NodeApi 精简版。
我们可以看到很多方法都是未实现的,大部分是一些同步的方法。还有 `polyfil` 中 `fetch` 方法并不支持大文件的传输,会内存着急的,这边的话就是用 `child_progress` 调用 `mac` 本身支持的 `curl` 命令去封装一下大文件下载的方法。
其实在开发过程中还是有很多不少的坑要去填,单纯的 js 侧来开发sketch插件的话,大体上来说开发效率和后期维护的话还是比较方便的。官方也是比较推荐用js来开发插件的。
开发中遇到的一些问题,比如 symbol 资源管理, 资源拖拽,解压缩, symbol 资源预览等之后也会分享其中的开发过程。
致谢
特别感谢优秀的设计师蔡衍、星格、文彪,他们在插件开发过程中给予的帮助。
特别感谢前端团队龙辉、亚鹏给与的开发建议以及和我一起开发的小伙伴 甜甜。
也感谢那些大牛们提供的开源项目支持,谢谢
参考文献
作者:大前端研发中心-FE研发部平台研发组-常庆宽
招聘信息
自如大前端研发中心招募新同学!
FE/iOS/Android工程师
公司福利有:
- 全额五险一金,并额外购买商业保险
- 免费健身房+年度体检
- 公司附近租房9折优惠
- 每年2次晋升机会
欢迎对技术有执着热爱的你加入我们!简历请投递 zhangxl122@ziroom.com, 或加微信 v-nice-v 详聊!