上一篇写了:从找一张图到做成产品:我定下的第一版边界。
里面有一条定得很清楚:正式形态是本地安装包。
落地交付时,我也试过把部分依赖留到安装后再联网拉取,好把首包做小。测下来问题很实际:网络波动、镜像失效、权限限制,任何一环失败,用户都会卡在「装上了却跑不起来」。最后还是定成:为了让不同机器上的运行环境保持一致,Node、Python、Redis、ffmpeg 以及相关运行时,全部打进安装包。
这条路我自己也反复想过合不合理。坦白说,Electron 应用自带运行时、音视频工具内嵌 ffmpeg,都很常见;但把业务后端、Redis、Python AI 一整条栈都塞进安装包,并不是最轻量的主流做法。很多产品会把首包做小,第一次打开再下载模型或运行时。那样下载更快,失败模式却更多,售后成本也更高。
对笑笑相册这种管电脑里长期影像库的本地相册,我更在意第一次打开稳不稳,而不是安装包能不能再瘦几百兆。所以最终还是选了「全量内嵌」:用体积和构建复杂度,换环境确定性。它不是最省流量的方案,但是和「本地、一致、少折腾」的产品目标是对齐的。
因此安装包从一开始就不是「一个前端壳 + 首次联网补齐」,而是自带完整本地运行时。
先说结论:安装包要装的,远不止一个前端页面
相册桌面版看起来是一个 App,里面其实至少有这些东西一起工作:
- Electron 壳:开窗与开屏,按序拉起并监控本机子进程;试用与买断激活、安装包完整性、媒体库目录也落在这一层
- 前端页面:媒体库浏览、搜索筛选、时间线 / 地点 / 人物 / 相似图、导入与设置等用户界面
- Node API 与后台 Worker:导入入库、本地数据库、搜索与相册业务;并把分析、云描述、逆地理、视频转码等任务丢进队列慢慢消化
- Redis:支撑这些后台队列,也承担导入去重一类需要快速读写的状态
- Python AI:本地做人脸检测与聚类、图像向量(以图搜图),以及相似图用的感知哈希;需要时再配合云端做画面描述
- ffmpeg / ffprobe:处理 HEIC 等难解码图片、读取视频信息、生成缩略图;部分视频在播放前还会按需转码
开发态可以分别启动;安装包态必须由主进程按顺序拉起、等待就绪、退出时再干净收掉。
换句话说,用户拿到的不是「一个网页套壳」,而是「一整套被打进安装包的本地服务」。
第一步:先让 Electron 跑起来
大概在今年四月,我先把产品推到 Electron 桌面形态。
那时候目标很朴素:同一套 Vue 业务代码,既能在浏览器里开发,也能在桌面窗口里打开。开发态仍然连本地 Vite;打包后再换成加载本地 dist。
很快又补了 Windows,并开始认真碰打包配置。这一步解决的是「像不像桌面应用」。
真正「像不像可交付产品」,要更后面。
第二步:发现只打前端远远不够
按常规划法,很多人会先做:前端 build → electron-builder 出 dmg/exe。
我也走过这一步。结果很清楚:
- 安装包能打开窗口
- 但接口没有人应答
- 分析能力更谈不上
因为开发时依赖 Vite 把 /api 代理到本机后端;安装包里没有 Vite 了。前端必须直连本机 API,而 API、Redis、Python 也得有人拉起------开发时这些是我手动开的,交付时就得交给壳来管。
所以接下来要补的,就不只是把页面打进包,而是:
把整条本地运行时一并打进包,并由 Electron 主进程编排。
现在启动大致是:开窗 / 开屏 → 拉起 Redis → 拉起 Python AI → 拉起 API → 健康检查通过 → 再进相册。退出时再统一停掉子进程,尽量不留僵尸服务占端口。
第三步:平台差异会把问题放大
macOS 和 Windows 不是改个图标就完事。
两边的 Python 环境、和系统架构绑定的本地扩展(比如数据库、图片处理那几块),再加上路径怎么写、程序文件叫什么------这些问题都会在打包阶段冒出来,Windows 和 macOS 都得各自花时间调通,没有捷径。对外发布时,两边理论上都该做代码签名;差别在于,Windows 上没签往往还能装,macOS 则严格很多------不但要签名,还要公证,少了这一环几乎过不了用户那一关。双击时经常会看到「已损坏,无法打开」一类提示:看起来像安装包坏了,其实是系统安全策略在拦。
顺带一提,未签名、未公证的包并非绝对不能用;自己调试时,终端里执行 xattr -dr com.apple.quarantine 应用路径,清掉隔离属性后往往就能打开,但这操作只适合开发者。给普通用户下载安装的产品,不可能让每个人装之前先敲命令。
最终打包被拆成了几条现实路径:
- 自用 / 本地调试:可更快迭代,甚至保留不签名版本
- 对外发布:签名、公证、校验更严
- CPU 架构也得分开准备。我只有 Apple 芯片的机器,Intel(x64)没有机器实测,所以 Mac 这边先发布 Apple 芯片版
第四步:第一次打开,才是真验收
有一个问题印象很深。
第一次安装打开时,内嵌服务还没就绪,界面已经往前冲,结果直接弹出报错。这个问题是我在一台比较旧的戴尔电脑上测试时发现的------我的 MacBook 开发机启动很快,这类时序问题常常测不出来。
后来调整了启动流程:放宽就绪等待上限,启动不顺会自动多试几次,避免还没就绪就弹错。服务一就绪就继续,不会故意拖慢正常启动,平时用也不受影响。开屏加载服务时还加了开屏弹窗,让用户始终知道应用正在启动,不必对着空白干等焦虑。
第五步:包会越打越大,于是开始剪裁
把 API、AI、模型相关资源都塞进去之后,体积和构建复杂度都会涨。
再往后就不是「怎么打出来」,而是「怎么打得更干净」:运行时用不到的东西,打包阶段尽量清掉。用户几乎看不见这项工作,但它直接决定安装包会不会越发越臃肿。
第六步:发布前再补校验与安全
剪裁解决的是体积,发布链路还要再补两道:
- 完整性校验,降低被改包的风险
- 安全策略前后端、Python 侧一起收紧
这些同样偏后台,但决定了安装包能不能长期作为正式产品分发。
还有一件产品上的小事:程序目录和照片目录要分开
安装包还有一个容易踩的产品坑:把海量图库默认塞进安装目录。
笑笑相册后来定的是:程序装在应用目录,媒体库根目录可以放到用户自己的大盘;不在安装向导里强制绑死。
这样升级应用时,不容易把照片数据一起搅乱。
看起来像设置项,其实是安装包产品化的一部分。
安装包交出去,才算过了交付这一关
功能可以在开发环境里先做出来。
产品要过的那一关,是别人机器上的第一次双击。
把这条路压缩一下,大概是:
先做成桌面壳 → 再把前端打进包 → 再把 API / Redis / AI 一并编排进包 → 再过 Windows / macOS 差异 → 再过首次打开的冷启动就绪 → 再过剪裁 → 再过完整性校验与安全收紧。
写在最后
独立开发桌面应用,最容易高估功能,低估交付。
相册这种带本地 AI 的应用,交付成本尤其高------因为你交付的不是页面,而是一整套本机运行时。