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

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

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

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

相关推荐
不可能片场5 小时前
自动化也会丢:一次 WorkBuddy 自动化清空的复盘
前端·electron
web打印社区2 天前
网页静默打印热敏小票:从 HTML 到出纸的完整指南
前端·javascript·vue.js·electron·pdf·html
ardss2 天前
ZCode 崩了,项目列表全丢:我从 69MB 日志里把数据一条条挖了出来
electron
「、皓子~3 天前
海狸IM 2.1 正式发布
flutter·微服务·golang·electron·开源软件·im·海狸im
明月_清风5 天前
🖥️ Electron 三进程 Host 实战:从架构设计到生产落地的完整指南
前端·electron·客户端
JienDa5 天前
我做了一款不依赖 AI 的离线传统术数排盘工具:Electron、Vue3 与 Java 17 的完整实践
java·人工智能·electron
晴天165 天前
多个 VS Code 项目会导致 Chrome 和 Electron 应用一起卡住?-Day30
前端·chrome·electron
刘广睿6 天前
独立开发桌面素材工作台的技术复盘:内置浏览器、下载队列与本地素材库
系统架构·electron·桌面应用·素材管理
爱丶不疚6 天前
BrowserWindow:你的Electron 应用可以不用手写红绿灯
前端·electron
楠楠子呀7 天前
号码验证技术解析:从原理到实践
运维·人工智能·ai·electron·自动化