Rescript 开源视频剪辑工具开发者指南:Electron 本地打包与 GitHub Actions 发布完整教程
Rescript 开源视频剪辑工具开发者指南:Electron 本地打包与 GitHub Actions 发布完整教程
Rescript 是一款完全离线运行的转写式(transcript-based)音视频剪辑开源工具——把视频丢进去,本地 Whisper 模型逐字转写,删掉文字对应的片段即被剪掉。它同时提供浏览器网页版和基于 Electron 的桌面应用,桌面版通过 GitHub Actions 实现三平台自动构建、签名、发布与自动更新。本文带你从源码跑起来,一路到本地打包出可安装的安装包,并拆解整套 CI 发布流程。
一、30 秒看懂项目结构
Rescript 前端基于 Next.js + React + TypeScript,桌面端由 electron/ 目录提供外壳。核心目录如下:
| 目录 / 文件 | 作用 |
|---|---|
app/、components/ |
Next.js 页面与 UI 组件(编辑器主体) |
| electron/main.ts | Electron 主进程:窗口、app:// 协议、菜单 |
| electron/media.ts | 桌面端媒体引擎:主进程中运行原生 ffmpeg 完成导出 |
| electron/updater.ts | 自动更新:读取 GitHub Release 的 latest-*.yml 清单 |
| scripts/build-electron.mjs | 用 esbuild 打包 Electron 主进程/preload |
| scripts/fetch-ffmpeg.mjs | 下载并校验各平台原生 ffmpeg 二进制 |
| scripts/after-pack.cjs | 打包钩子:校验 ffmpeg 已进入安装包 |
| .github/workflows/release.yml | 发布工作流(tag 触发,三平台矩阵) |
| .github/workflows/ci.yml | 日常 CI:lint、类型检查、测试、构建 |
📖 完整的发布文档见 RELEASING.md,是理解本文最权威的参考。
二、本地一键启动:Web 版与桌面开发模式
克隆仓库并安装依赖(postinstall 会自动应用补丁并拷贝 WASM 资产):
git clone https://gitcode.com/gh_mirrors/resc/rescript
cd rescript
npm install
两条最常用的启动命令(定义在 package.json 的 scripts 中):
npm run dev—— 启动 Next.js 开发服务器(http://localhost:3000),体验网页版编辑器npm run electron:dev—— 同时拉起 Next.js 开发服与 Electron 窗口
第二条命令的巧妙之处在于 scripts/electron-dev.mjs:它会先轮询 http://localhost:3000 直到有响应,再启动 Electron,避免窗口抢跑开发服务器导致的白屏竞态。
开发期自动更新是禁用的,仅当 app.isPackaged 为 true(即打包后的应用)才会检查更新,见 electron/updater.ts。
三、Electron 桌面端架构:为什么安装包里没有 node_modules
理解桌面端的关键是明白渲染层装的是什么。npm run dist 会先执行 export:desktop(STATIC_EXPORT=1 NEXT_PUBLIC_ELECTRON=1 next build),产出一份 Next.js 静态导出目录 out/;再由 esbuild 把 Electron 主进程和 preload 各自压成单个 JS 文件(scripts/build-electron.mjs)。
于是安装包的内容非常"干净":
- 渲染层 = 静态
out/(Next.js、transformers.js、ffmpeg.wasm 全部已内联其中) - 主进程 =
electron-dist/main.js+preload.js两个打包文件,不携带任何node_modules - 原生 ffmpeg = 通过 build.extraResources 塞进
resources/ffmpeg/的静态二进制
主进程通过自定义 app:// 特权协议加载静态导出(electron/main.ts),并自行注入 COOP/COEP 响应头——因为 GitHub Pages 给不了这些跨源隔离头,而 SharedArrayBuffer 是 ffmpeg.wasm 多线程的硬性前提。
为什么桌面端要用原生 ffmpeg? 浏览器版 ffmpeg.wasm 的堆上限是 2 GiB,整个渲染结果都驻留内存,长视频和 4K 导出必然失败。桌面端改为在主进程直接跑静态 ffmpeg,源文件从磁盘读、结果写临时文件,内存不再是瓶颈(electron/media.ts)。
四、本地打包:一条命令产出三平台安装包
在干净的工作区执行:
npm run dist # 未签名的桌面安装包,输出到 dist/
这一条命令实际串联了三步(见 package.json):
export:desktop—— Next.js 静态导出到out/build:electron+fetch:ffmpeg—— 打包主进程、下载 ffmpegelectron-builder—— 按 build 配置 产出各平台安装包
其中 fetch:ffmpeg 值得单独看:它下载固定版本的 ffmpeg-static(b6.1.1)对应各架构的二进制,并逐一核对 SHA-256 摘要,落到 build/ffmpeg/<os>-<arch>/ 目录。而 scripts/after-pack.cjs 是打包流水线上的"保险丝"——如果 ffmpeg 没被正确拷入安装包,它会直接让构建失败,而不是让用户静默降级到 wasm 引擎再撞内存墙。
各平台产物目标在 package.json 的 build 段里一目了然:macOS 出 DMG/ZIP(x64 + arm64,含签名与公证配置)、Windows 出 NSIS 安装器、Linux 出 AppImage 与 deb。
五、GitHub Actions 发布流程拆解
5.1 触发方式:推送 v*.*.* tag
发布工作流 .github/workflows/release.yml 只被语义化版本 tag 触发,使用矩阵在 macOS / Ubuntu / Windows 三台独立 runner 上并行构建(fail-fast: false,一个平台失败不拖累其他平台)。
每个平台的步骤基本一致:
npm ci+ 类型检查(web 与 electron 两套 tsconfig 都查)- macOS 额外解码 App Store Connect API key,用于公证
- 执行
npm run release=npm run dist+electron-builder --publish always,把安装包和latest-*.yml更新清单一并上传为 draft Release - Ubuntu 节点顺带上传 Sentry source maps(
continue-on-error: true,绝不阻塞发布)
5.2 最后一步:draft 变 published 的"闸门"
publish job 依赖全部三个平台 job 成功才运行(release.yml):
- 解析上一个 tag,对两 tag 之间的 diff 用 AI 生成 Release Notes(
npm run notes:preview可在本地预览) - 执行
gh release edit --draft=false --latest,把 draft 翻转为正式发布
这个设计的意义:自动更新只拉取 published 的 Release,所以任何一次构建残缺(比如 Windows 挂了),用户都绝不会收到只有两个平台的"半套"更新。
5.3 配套 CI:每次 push 到 main 的质量闸门
.github/workflows/ci.yml 在每次 push / PR 时跑 lint、web 与 electron 双套类型检查、i18n 与时间线导出测试、真实 ffmpeg 渲染测试(复用与桌面应用相同的静态 ffmpeg 构建),最后完整构建 Next.js 与 Electron 主进程——发布流程里的所有构建步骤,在 CI 里都已经被"预演"过。
六、打一个新版本:发布者的日常操作流
维护者发版只需三步,全部有现成脚本(package.json):
npm run cut:patch # 或 cut:minor / cut:major
它封装了 npm version <type> && git push --follow-tags:递增 package.json 的版本号 → 提交 Release vX.Y.Z → 打同名 tag → 推送。tag 一到远端,第五节描述的发布流水线自动接管,剩下的就是看 Actions 日志。
⚠️ 注意:
npm version拒绝在工作区有未提交改动时运行,发版前请先 commit。另外 macOS 签名需要仓库配好CSC_LINK、APPLE_API_KEY等 Secrets(完整清单见 RELEASING.md 的表格)。
七、常见问题速查
| 现象 | 原因与对策 |
|---|---|
构建失败提示 native ffmpeg missing |
先跑 npm run fetch:ffmpeg,after-pack 钩子在拦截缺件的安装包 |
| 打包后桌面应用回退到 wasm 引擎 | 检查 resources/ffmpeg/ 是否存在;可用 RESCRIPT_MEDIA_ENGINE=wasm 强制 wasm 排查 |
| Windows-on-ARM 上应用无法启动 | 需 arm64 构建:x64 版在 WOA 模拟下 V8 拿不到 SSE4.1,Wasm SIMD 无法启用(见 RELEASING.md) |
本地 electron:dev 白屏 |
多为开发服务器未就绪,确认 ELECTRON_START_URL 指向且 3000 端口已响应 |
小结
Rescript 的桌面端工程化值得借鉴:静态导出 + esbuild 让安装包摆脱 node_modules 依赖;after-pack 钩子把"静默降级"变成"响亮失败";draft → published 的两段式发布确保自动更新永不推送残缺版本。从 npm run electron:dev 到 npm run cut:patch,你只需要记住这两条命令,中间的全部复杂性都已经被脚本和 CI 收编了。


