从开发调试到用户能下载安装:我把相册打成安装包的经历

上一篇写了:从找一张图到做成产品:我定下的第一版边界。

里面有一条定得很清楚:正式形态是本地安装包。

落地交付时,我也试过把部分依赖留到安装后再联网拉取,好把首包做小。测下来问题很实际:网络波动、镜像失效、权限限制,任何一环失败,用户都会卡在「装上了却跑不起来」。最后还是定成:为了让不同机器上的运行环境保持一致,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 的应用,交付成本尤其高------因为你交付的不是页面,而是一整套本机运行时。

相关推荐
mont evergreen1 天前
一封从外部世界寄来的信:二维码数据如何穿越三重门,抵达你的屏幕
electron·vue·事件
fellow992 天前
DSH Desktop:把 DeepSeek Harness 变成真正的桌面应用
electron·agent·ai编程·deepseek
CDwenhuohuo3 天前
electron pc项目打包成桌面端
前端·javascript·electron
不可能片场4 天前
命令行中文变问号 我用环境变量救了场
前端·electron
不可能片场4 天前
AI视频口型对齐 用音频驱动说话镜头
前端·electron
Zoom5 天前
【开源】7 天,我用 Rust 复刻了 FinalShell!Rhost v1.0.0 发布
rust·electron·shell
爱丶不疚6 天前
Electron: Sentry 都采集了什么?你知道吗
前端·electron
格数致用6 天前
03- Luckysheet与Vue3+Electron集成实战指南
electron·vue3·luckysheet
fellow998 天前
Electron + pnpm 在鸿蒙应用里跑起来
electron·harmonyos·openharmony·deepseek·deepseekharness
记得开心一点嘛8 天前
Trellora:基于 Electron、React 和本地知识库的 AI 知识工作台
人工智能·react.js·electron