东营码良软件开发
  • 首页
  • 产品与服务
    抖音软件小程序开发网站建设小程序开发价格网站建设费用微信商城小程序源码交付APP定制开发建站公司选择
  • 开发案例
  • 新闻资讯
    二级菜单A
  • 关于我们
  • GEO 优化
  • Ai超市
咨询客服咨询客服
企业咨询
东营码良软件开发
首页›
产品与服务›
开发案例›
新闻资讯›
二级菜单A›
关于我们›GEO 优化›Ai超市›
会员中心
首页产品与服务开发案例新闻资讯我的
Dongying Maliang Software

码良软件开发

企业软件开发·微信小程序·网站建设·GEO 优化·AI 应用落地

咨询客服

导航

  • 首页
  • 产品与服务
  • 开发案例
  • 新闻资讯
  • 关于我们
  • GEO 优化
  • Ai超市

服务

  • 软件开发定制
  • GEO 搜索优化
  • 软件资源商城
  • 会员服务
  • 在线客服

行业方案

  • 零售门店
  • 教育培训
  • 医疗健康
  • 商务服务
  • 本地生活
  • 生产制造

联系电话

1886546092715154670927

地址

山东省东营市垦利区兴隆路8-5号

扫码

码良软件开发 · 品牌入驻
品牌入驻手机端查看商城、案例与在线咨询

Copyright © 2019-2026 东营码良软件开发 Inc. 版权所有鲁ICP备2025202136号-2
开发资讯 > 资讯详情

Recordly 开发文档(中文)格式对比

2026-09-20 14:47:54阅读 8
广告
码良软件/小程序开发

码良软件/小程序开发

全栈技术团队 + 资深工程师开发 · 按需定制 · 源码交付 · 长期维护 · 东营本地可对接

小程序定制API接口设计bug修复升级改版软件开发企业管理系统
立即咨询 18865460927备用电话 15154670927

语言: 简体中文 · 对应版本 Recordly v1.4.0(main 分支,HEAD 4992686)

Recordly 开发文档(中文)

本文面向要改代码的人,讲清楚三件事:这套东西怎么跑起来、代码分成哪几块、改了之后怎么验证。
面向用户的功能介绍请看 README.zh-CN.md。


目录

  1. 技术栈
  2. 环境准备
  3. 快速开始
  4. 目录结构
  5. 构建流水线
  6. 多窗口体系
  7. IPC 架构与安全策略
  8. 原生层
  9. 渲染层:录制端与编辑器
  10. 数据与文件位置
  11. 国际化
  12. 测试
  13. 代码规范
  14. 环境变量与调试开关
  15. 打包与发布
  16. CI 质量门禁
  17. 常见问题
  18. 贡献流程

1. 技术栈

Recordly 是 Electron 桌面应用,不是 Web 应用。这一点决定了后面所有分层:主进程管窗口/文件/原生能力,渲染进程管 UI,preload 做唯一的安全桥。

层选型
桌面壳Electron 43.1
构建Vite 5.1 + vite-plugin-electron 0.28
渲染React 18.2 + TypeScript 5.2(strict: true)
样式Tailwind CSS 3.4 + Tailwind Animate
基础组件Radix UI 全家桶(shadcn 风格,见 src/components/ui/)
图标@phosphor-icons/react / react-icons
动效motion 12
画布 / 合成pixi.js 8.14 + pixi-filters
视频容器 / 解复用mediabunny、mp4box、web-demuxer、@fix-webm-duration/fix
转码 / 封装ffmpeg-static、ffprobe-static
录制capturekit、uiohook-napi(全局键鼠钩子)
时间线交互dnd-timeline、react-resizable-panels、react-rnd
Lint / 格式Biome 2.3(不是 ESLint + Prettier)
测试Vitest 3.2(environment: node)
打包electron-builder 26(NSIS / dmg / zip / AppImage)
自动更新electron-updater(GitHub Releases)
许可证AGPL-3.0(见 LICENSE.md)

规模参考:src/ + electron/ 共 488 个 .ts/.tsx(其中 86 个 .tsx),134 个测试文件。


2. 环境准备

通用

  • Node.js 22(CI 固定用 22;本机 22.x 即可)
  • npm(仓库带 package-lock.json,请用 npm ci 或 npm install,不要混用 pnpm/yarn,否则 postinstall 的原生流程可能对不上)
  • git

各平台额外依赖

平台需要装什么用途
WindowsVisual Studio 2022(或 Build Tools),勾选 C++ 工作负载 + CMake编译 WGC 采集、DXGI 回退、光标监控、GPU 导出等 C++ 辅助程序
macOSXcode Command Line Tools(xcode-select --install)swiftc 编译 ScreenCaptureKit 辅助程序
Linuxbuild-essential cmake libx11-dev libxt-dev libxtst-dev libxkbfile-dev libxi-dev libxrandr-dev libxinerama-dev编译原生辅助程序 + uiohook-napi 的 X11 依赖
Windows 不装 CMake 也能跑起来。 详见 5.3 字幕运行时。

系统版本下限

平台最低版本原因
macOS14.0 (Sonoma)ScreenCaptureKit 系统音频 / 麦克风能力
Windows10 20H1(Build 19041)原生 WGC 采集与最佳光标隐藏行为
Linux任意现代发行版走 Electron 采集 API;系统音频一般要 PipeWire

3. 快速开始

git clone https://github.com/webadderallorg/Recordly.git recordly
cd recordly
npm install      # 注意:会触发原生编译,首次较慢
npm run dev

npm install 到底做了什么

不要以为它只是拉包。package.json 里的 postinstall 会依次执行两步,任何一步失败都会让 npm install 以退出码 1 结束:

  1. npm run rebuild:native → electron-rebuild --force --only uiohook-napi
    把全局键鼠钩子模块按 Electron 的 ABI 重编译。跳过这步,运行时 uiohook-napi 会报 ABI 不匹配。
  2. npm run build:platform-native-helpers → 依次构建:
    • build:whisper-runtime(字幕引擎,见下)
    • build:native-helpers(macOS Swift 辅助程序,非 mac 直接跳过)
    • build:windows-capture、build:windows-gpu-export、build:nvidia-cuda-compositor、build:cursor-monitor(Windows / CUDA)

只想改前端、不想编译原生代码

CI 就是这么干的,本地同样适用:

npm ci --ignore-scripts            # 跳过 postinstall
node node_modules/ffmpeg-static/install.js
npx electron-builder install-app-deps
npm run dev

代价是没有原生采集后端,会退回浏览器采集 / ffmpeg 路径。

开发模式的一个关键点

npm run dev 跑的是 vite --config vite.config.ts。当 VITE_DEV_SERVER_URL 存在时:

  • electron/appPaths.ts 会把 userData 切到 Recordly-dev,和正式版数据完全隔离;
  • 不申请单实例锁(shouldEnforceSingleInstanceLock = !IS_DEV),方便同时开多个实例调试。

所以你的开发数据在 %APPDATA%\Recordly-dev,删掉它等于恢复出厂设置。


4. 目录结构

Recordly/
├── electron/                  # 主进程(Node 侧)
│   ├── main.ts                # 入口:窗口、菜单、托盘、权限、GPU 开关
│   ├── preload.ts             # contextBridge,暴露 window.electronAPI
│   ├── electron-env.d.ts      # ★ electronAPI 的类型定义(改 API 必须同步这里)
│   ├── windows.ts             # 各类窗口的创建与生命周期
│   ├── appPaths.ts            # userData / recordings 路径(含 dev 隔离)
│   ├── mediaServer.ts         # 本地媒体 HTTP 服务(给 <video> 喂文件)
│   ├── rendererServer.ts      # 打包后渲染资源服务
│   ├── updater.ts             # electron-updater 封装
│   ├── navigationPolicy.ts    # 外链策略
│   ├── permissionPolicy.ts    # 媒体 / 屏幕采集权限策略
│   ├── gpuSwitches.ts         # 平台相关 GPU 命令行开关
│   ├── cursorHider.ts         # 录制时隐藏系统光标
│   ├── ipc/                   # ★ IPC 层
│   │   ├── handlers.ts        # 注册总入口
│   │   ├── constants.ts       # 频道名与常量
│   │   ├── types.ts
│   │   ├── register/          # 按功能拆分的注册模块
│   │   ├── captions/          # whisper 字幕(解析、分段、静音检测)
│   │   ├── cursor/            # 光标遥测
│   │   ├── export/            # 导出流、原生视频导出
│   │   ├── ffmpeg/            # ffmpeg 二进制探测与滤镜
│   │   ├── project/           # 项目文件的原子保存
│   │   ├── recording/         # 录制(windows / mac / ffmpeg 三条实现)
│   │   └── settings/          # 设置持久化
│   └── native/                # ★ 原生源码 + 预编译产物
│       ├── *.swift            # macOS 辅助程序
│       ├── wgc-capture/       # Windows Graphics Capture(C++)
│       ├── windows-capture/   # DXGI 回退(C++)
│       ├── cursor-monitor/    # 光标监控(C++)
│       ├── gpu-export-probe/  # GPU 导出能力探测(C++)
│       ├── nvidia-cuda-compositor/  # CUDA 合成(.cu)
│       └── bin/<平台-架构>/    # 预编译产物,随包发布
├── src/                       # 渲染进程(React)
│   ├── main.tsx / App.tsx     # 按 windowType 分发窗口
│   ├── components/
│   │   ├── launch/            # 录制端:HUD、源选择、倒计时、更新提示
│   │   ├── video-editor/      # 编辑器:时间线、导出、预览、项目、预设
│   │   ├── ui/                # Radix 封装的基础组件
│   │   ├── announcements/     # 公告
│   │   └── countdown/
│   ├── lib/
│   │   ├── exporter/          # ★ 导出引擎(帧渲染、编码、音频、封装)
│   │   ├── announcements.ts / appSettings.ts / wallpapers.ts ...
│   │   └── geometry/
│   ├── contexts/              # I18nContext / ThemeContext / ShortcutsContext
│   ├── hooks/                 # useScreenRecorder、设备枚举、音量表
│   ├── i18n/                  # 10 语言 × 7 命名空间
│   ├── utils/                 # 比例换算、平台判断
│   └── assets/                # 光标素材(macOS / Tahoe / Windows 11 三套)
├── scripts/                   # 构建与发布脚本(.mjs)
├── public/                    # 静态资源:应用图标、壁纸、wasm
├── build/                     # macOS entitlements
├── branding/                  # 品牌源素材
├── docs/                      # 公告说明 + README 用媒体
├── icons/                     # 打包图标(icns / ico / png)
└── .github/workflows/         # CI 与发布流水线

三个入口别搞混:

入口文件说明
主进程electron/main.ts构建后是 dist-electron/main.cjs
preloadelectron/preload.ts构建后同目录
渲染进程index.html → src/main.tsx → src/App.tsx构建后是 dist/

@ 别名指向 src/,在 vite.config.ts、vitest.config.ts、tsconfig.json 三处都配了,新增构建入口记得同步。


5. 构建流水线

5.1 dev 与 build 的区别

命令实际动作
npm run devvite --config vite.config.ts。vite-plugin-electron 顺带编译主进程与 preload 并拉起 Electron
npm run buildbuild:platform-native-helpers → tsc → vite build → normalize:electron-main-cjs → smoke:electron-main-cjs → electron-builder
npm run build:win / :mac / :linux同上,最后换成 electron-builder --win / --mac / --linux

产物:dist/(渲染)、dist-electron/(主进程 + preload)、release/(安装包,electron-builder 的 directories.output)。

5.2 主进程为什么强制 CJS

vite.config.ts 里有三个不显眼但很关键的设计:

  1. electronMainCjsOutputPlugin 强制 lib.formats = ["cjs"]、入口文件名 .cjs。
    原因写在注释里:Vite 的 mergeConfig 会把 lib.formats 和插件的 ESM 默认值拼接在一起,导致输出格式不确定。
  2. inlineDynamicImports: true:主进程打成单文件,避免 Electron 加载动态 chunk 时的路径问题。
  3. electronMainCjsGuardPlugin:closeBundle 阶段调用 scripts/smoke-electron-main-cjs.mjs 做冒烟检查,失败就让整个 vite build 抛错。
    也就是说构建产物格式一旦退化,构建会立刻中断而不是留到运行时报错。
排查构建问题先看 npm run smoke:electron-main-cjs,它是这套机制的真相来源。

5.3 字幕(whisper)运行时

scripts/build-whisper-runtime.mjs 的逻辑值得单独讲,因为它决定了「Windows 上要不要装 CMake」:

  1. 优先走预编译:Windows x64 会下载 whisper.cpp 官方 whisper-bin-x64.zip(版本 v1.8.4,带 SHA-256 校验),解压后取出 whisper-cli.exe 与相关 DLL,写入 electron/native/bin/win32-x64/。
  2. 下载失败才回退源码编译:需要 CMake + VS。Windows 上生成器按 VS 2026 → VS 2022 → VS 2019 顺序自动回退(见 scripts/windows-cmake-generators.mjs)。
  3. 缺 CMake 的失败策略分场合:
    • postinstall / CI=true / WHISPER_RUNTIME_ALLOW_MISSING=1 → 只警告,退出 0;
    • 直接调用 npm run build、build:win 等 → 硬报错,避免打出一个静默缺失字幕能力的安装包。
  4. 已 staged 会跳过重复构建,判断依据是同目录下的 whisper-runtime.json 清单(版本 + 架构 + 二进制存在)。

5.4 生产构建的两个坑

  • terser 会删掉 console.log / console.debug(drop_console: true、drop_debugger: true)。
    所以「本地有日志、打包装没有」是预期行为,别为此加 console.error。
  • manualChunks 只分了三块:react-vendor、video-processing(mediabunny / mp4box / fix-webm-duration)。往 src/lib/exporter/ 里引重库时注意别把主 chunk 撑爆(chunkSizeWarningLimit 已放宽到 1000 kB)。

5.5 打包配置要点(electron-builder.json5)

  • appId: dev.recordly.app,asar: true。
  • asarUnpack:ffmpeg-static、ffprobe-static、uiohook-napi、electron/native/bin/** 必须解包,因为要以真实文件路径去 exec。
  • extraResources:public/wallpapers → assets/wallpapers(壁纸不进 asar)。
  • 剥离:!dist/wallpapers/**、whisper-bench*、whisper-quantize*、whisper-server*、whisper-vad-speech-segments* 等调试用二进制不进包。
  • macOS:hardenedRuntime: true + 两个 entitlements 文件;extendInfo 里声明了相机 / 麦克风 / 音频采集用途说明,并注册了 .recordly 文档类型。
  • Windows:NSIS,可选安装目录、建桌面与开始菜单快捷方式。
  • publish:GitHub Releases(webadderall/Recordly,tag 前缀 v),publishAutoUpdate: true。

6. 多窗口体系

这是 Recordly 最容易让人迷路的地方:一个渲染入口,多个窗口身份。

src/App.tsx 从 URL 查询参数读 windowType,然后分发组件:

windowType组件窗口特点
hud-overlaycomponents/launch/HudWindow无边框透明浮层,主入口(启动即它)。开启 HTML 级鼠标穿透,hudOverlaySetIgnoreMouse(true)
source-selectorcomponents/launch/SourceSelector透明背景;挑选屏幕 / 窗口
countdowncomponents/countdown/CountdownOverlay录制前倒计时浮层
update-toastcomponents/launch/UpdateToastWindow透明、overflow: visible,仅 macOS 使用
editorcomponents/video-editor/EditorWindow主编辑器窗口

主进程侧的窗口创建集中在 electron/windows.ts:createHudOverlayWindow / createSourceSelectorWindow / createEditorWindow / showUpdateToastWindow。

判断一个窗口是不是编辑器,用的是 URL 里有没有 windowType=editor:

function isEditorWindow(window: BrowserWindow) {
  return window.webContents.getURL().includes("windowType=editor");
}

所以改窗口 URL 参数会直接破坏主进程逻辑,别随手改。

平台差异(都是踩过的坑,注释里写得很细)

  • 托盘只在 Linux 启用(shouldUseTray())。macOS / Windows 走 Dock / 任务栏。
  • Win32 HUD 的鼠标穿透脆弱:开启穿透(Win11+)后,对透明 HUD 调 show/moveTop/focus 会永久破坏 setIgnoreMouseEvents 转发,窗口变成彻底点不透。所以托盘唤醒时用 showInactive() + 重新断言鼠标状态。Win10 不支持穿透,HUD 常驻可交互,反而可以正常 show/restore。
  • Linux Wayland 焦点问题:合成器忽略 focus()。做法是干脆销毁并重建 HUD 窗口(创建路径能拿到焦点),注释里点名提到了 XDG activation token 的缺失。
  • Linux Wayland 屏幕共享只弹一次 portal:setDisplayMediaRequestHandler 里,若源 id 是哨兵 screen:linux-portal 或为空,跳过 desktopCapturer.getSources(),直接返回合成 id——因为 getSources() 本身就会触发一次 portal。

关闭编辑器的行为

Windows 上关闭编辑器不是关窗口,而是隐藏它并重新显示 HUD(closeEditorWindowToHud),目的是让录制收尾(例如摄像头文件 finalize)继续在渲染进程里跑完,同时应用回到「随时可录」状态。有未保存改动时弹三选一:保存关闭 / 放弃关闭 / 取消。


7. IPC 架构与安全策略

7.1 桥的形态

  • electron/preload.ts 通过 contextBridge 暴露 window.electronAPI。
  • 类型定义集中在 electron/electron-env.d.ts 的 interface Window 里,约 700 行,覆盖录制、导出、项目、字幕、更新、权限等全部能力。
  • 新增或修改 API 必须同步这个 .d.ts,否则渲染进程拿不到类型(并且 Biome 对该文件单独放宽了 noNamespace 和 noExplicitAny,说明它是有意保持集中的)。

7.2 主进程侧的注册方式

  • 总入口:electron/ipc/handlers.ts(同时负责 cleanupNativeVideoExportSessions、cleanupAllExportStreams、killWindowsCaptureProcess 等清理)。
  • 按功能拆到 electron/ipc/register/:
    announcements、assets、captions、export、exportCaptionSidecars、permissions、project、recording、settings、sourceMapping、sources。
  • 频道名用 kebab-case,例如 set-has-unsaved-changes、hud-overlay-close、request-save-before-close。
  • 有些频道直接写在 main.ts 里(更新相关的 install-downloaded-update、check-for-app-updates 等),因为它们要拿到 mainWindow 这类窗口引用。

加一个 IPC 的标准动作: 在对应 register/*.ts 里注册 → 在 preload.ts 暴露 → 在 electron-env.d.ts 补类型 → 渲染层调用。

7.3 安全策略(三道闸)

  1. 导航策略(navigationPolicy.ts):web-contents-created 时统一加固,外链一律 shell.openExternal,不在应用内导航。
  2. 媒体权限策略(permissionPolicy.ts + main.ts 里的 setPermissionCheckHandler / setPermissionRequestHandler):
    只有可信采集窗口(即 HUD 主框架)且来源在可信 URL 列表内才放行 media 权限。可信列表 = dist/index.html 的文件 URL + dev server URL + 打包后的本地渲染服务地址。
  3. 设备权限直接全拒:setDevicePermissionHandler(() => false) —— Recordly 不使用 WebHID / Web Serial / WebUSB,默认不授予任何设备。

另外 setDisplayMediaRequestHandler 接管了 getDisplayMedia():渲染层调它不会弹系统选择器,而是落到用户预选的源上。这里有个必须遵守的约束(注释明确警告):

回调只能传 纯 { id, name } 的 video 对象。如果图省事把完整的 DesktopCapturerSource(带 thumbnail、appIcon 等)强转过去,会破坏 Electron 内部的光标约束传播,导致渲染层设的 cursor: 'never' 被原生采集管线静默忽略。

8. 原生层

electron/native/ 是「JS 干不了的事」的落点。预编译产物提交在 electron/native/bin/<平台-架构>/ 并随包发布,所以普通开发不需要每次都编原生代码。

macOS(Swift,只在 macOS 上编译)

scripts/build-native-helpers.mjs 在非 macOS 平台直接跳过。用 swiftc 为 arm64-apple-macos14.0 和 x86_64-apple-macos14.0 两个目标各编一份:

源文件产物作用
ScreenCaptureKitRecorder.swiftrecordly-screencapturekit-helperScreenCaptureKit 录制(含系统音频)
ScreenCaptureKitWindowList.swiftrecordly-window-list窗口列表枚举
SystemCursorAssets.swiftrecordly-system-cursors导出系统光标素材(用于编辑器里重绘光标)
NativeCursorMonitor.swiftrecordly-native-cursor-monitor原生光标位置 / 类型采样

缺 swiftc 会直接抛错并提示安装 Xcode Command Line Tools。

Windows(C++ / CMake)

目录产物作用
wgc-capture/wgc-capture.exe当前实际编译的 Windows 采集辅助程序:Windows Graphics Capture + Media Foundation 编码 + WASAPI loopback 系统音频
cursor-monitor/cursor-monitor.exe光标遥测(位置、类型、点击事件)
gpu-export-probe/recordly-gpu-export.exeGPU 导出能力探测
nvidia-cuda-compositor/recordly-nvidia-cuda-compositor.exeCUDA 合成(实验性,需 NVIDIA 显卡 + CUDA 工具链)
windows-capture/—含 DXGI 回退实现(dxgi_session.cpp),但当前没有任何构建脚本引用它,属遗留代码。别误以为它在打包里

Windows 生成器自动回退顺序:Visual Studio 18 2026 → 17 2022 → 16 2019,并会清理 CMakeCache.txt 与 CMakeFiles 后重试。

脚本对已提交的预编译产物也很友好:找得到 CMake 就源码编译,找不到但 bin/ 里已有现成 wgc-capture.exe 就直接复用(并校验清单),两边都不满足才报错退出。

辅助程序清单(helpers-manifest)

scripts/native-helper-manifest.mjs 会为每个原生辅助程序生成 / 校验 helpers-manifest.json:记录源目录与二进制的对应关系。构建时更新,打包冒烟测试时校验。改原生源码后发现产物没更新,先看这个清单的告警。

与主进程的衔接

  • 二进制寻址:electron/ipc/paths/binaries.ts(配套测试 binaries.test.ts)。
  • 打包后路径校验:npm run smoke:packaged-binaries 会检查打包产物里的原生二进制是否都在位——CI 三个平台都会跑这一步。

9. 渲染层:录制端与编辑器

9.1 录制端(src/components/launch/)

HUD 是常驻入口,内部按功能拆开:

  • HudWindow.tsx + LaunchWindow.tsx:主体与外壳
  • popovers/:MicPopover、WebcamPopover、SourcePopover、ProjectPopover、MorePopover、CountdownPopover,由 LaunchPopoverCoordinator 统一协调(同时只允许一个弹出层)
  • hooks/:useLaunchWindowActions、useLaunchWindowSystemState、useRecordingTimer、useHudBarDrag、useWebcamPreviewOverlay、useLaunchHudInteractionState
  • hudMousePassthrough.ts / hudViewportBounds.ts / floatingWebcamPreview.ts:注意这三个都带独立测试,说明它们是易碎逻辑,改动务必跑测试
  • contexts/HudInteractionContext:HUD 交互态共享

9.2 编辑器(src/components/video-editor/)

体量最大的子系统,按职责再分层:

子目录 / 文件职责
layout/外壳:EditorShell、EditorHeader、EditorSidebar、EditorPreviewPanel、EditorTimelinePanel、各类 Dialog 汇总
timeline/时间线子系统,见下
videoPlayback/预览引擎:缩放变换、光标跟随相机、光标渲染、场景动效、播放速率、webcam 同步
export/导出控制器、进度、设置、持久化、冒烟导出自动化
project/项目生命周期、打开/保存动作、快照模型、项目库
state/useProjectState、useTimelineState、useEditorUiState、useAppearanceState
presets/预设与偏好持久化
audio/片段音频、预览同步、波形(含 Web Worker waveform.worker.ts)
captions/自动字幕控制器
hooks/区域命令(缩放 / 裁剪 / 注释 / 音频 / 字幕 / 片段)、全局交互、历史记录、时间线投影

这一层的架构约定:纯逻辑抽成同名 .ts 并配 .test.ts,React 组件只做装配。
例如 clipSplit.ts / clipSplit.test.ts、zoomTransform.ts / zoomTransform.test.ts、editorHistory.ts / editorHistory.test.ts。要改行为,先改并测那个 .ts,再动组件。

时间线子系统内部:

timeline/
├── core/        rows / spans / time / constants / timelineTypes(纯函数,全部有测试)
├── model/       timelineModel.ts(带测试)
├── dnd/         engine.ts(拖拽引擎,带测试)
├── hooks/       runtime、归一化、范围、选择、键盘快捷键、DnD 绑定、音频峰值
│   ├── actions/ 音频 / 字幕 / 缩放区域动作
│   └── utils/   放置、通知、选择工具(带测试)
├── components/  axis / markers / overlays / playhead / toolbar / viewport / waveform / wrapper
├── Item.tsx / Row.tsx / TimelineEditor.tsx
└── sourceAudioTracks.ts / timelineLayout.ts / zoomSuggestionUtils.ts

9.3 导出引擎(src/lib/exporter/)

这是「录完之后怎么出片」的核心,也是测试最密的目录(27 个测试文件)。三条路线:

  1. 原生静态布局导出(快,主流):nativeStaticLayoutRoutePlan.ts 决定走 cuda-overlay / cuda-scale-cpu-pad / cuda-static-composite / nvidia-cuda-compositor / windows-d3d11-compositor 哪条,再由 IPC 调原生合成器,最后用 muxer.ts 封装。
  2. 原生逐帧导出:nativeVideoExport.ts(主进程)+ nativeFrameCapture.ts / modernFrameRenderer.ts(渲染侧),支持 rawvideo 与 h264-stream 两种输入模式。
  3. 浏览器导出回退:modernVideoExporter.ts / videoExporter.ts,带 streamingDecodePipeline / streamingDecoder 流式解码。

音频侧:audioRoutingEngine 决定路由,sourceTrackRoutingPolicy / editedTrackStrategy 决定「直接复制源音轨」还是「离线渲染编辑后的音轨」,audioEncoder / offlineAudioProcessor 负责编码,exportBitrate / exportTuning / videoColorSpace 管参数。

其他:gifExporter.ts(GIF 输出)、captionRenderer.ts / annotationRenderer.ts(字幕与注释烧录)、exportSavePolicy.ts(保存策略,含覆盖确认)、finalizationTimeout.ts(收尾超时保护)、backendPolicy.ts(后端选择)。

backendPolicy 与 exportSavePolicy 这类"策略"文件都带测试,改判断条件时务必先看测试里约定的优先级。


10. 数据与文件位置

userData 根目录

环境路径
开发(VITE_DEV_SERVER_URL 存在)app.getPath("appData")/Recordly-dev(Windows 即 %APPDATA%\Recordly-dev)
正式app.getPath("userData"),产品名 Recordly

目录与文件清单(electron/ipc/constants.ts)

名称位置说明
录像目录<userData>/recordings可被用户改到别处(chooseRecordingsDirectory)
项目目录<userData>/Projects默认项目存放地
最近项目<userData>/recent-projects.json最多 16 条
快捷键<userData>/shortcuts.json
录制设置<userData>/recordings-settings.json麦克风 / 系统音频 / 摄像头
倒计时设置<userData>/countdown-settings.json
应用设置<userData>/app-settings.json
whisper 模型<userData>/whisper/ggml-small.bin从 HuggingFace 下载

文件格式约定

后缀含义
.recordly项目文件(JSON)。兼容旧后缀 .openscreen
.preview.png项目缩略图
.recordly-session.json录制会话清单
recording-*自动录像文件名前缀

自动清理策略

自动录像保留 最近 20 个 且 不超过 14 天(AUTO_RECORDING_RETENTION_COUNT / AUTO_RECORDING_MAX_AGE_MS),逻辑在 electron/ipc/recording/prune.ts(带测试)。

光标遥测

  • 版本 CURSOR_TELEMETRY_VERSION = 2,采样间隔 33ms(约 30Hz),上限 1 小时 样本量。
  • 数据点包含位置、点击类型、光标类型,供编辑器的缩放建议与光标重绘使用。

11. 国际化

  • 支持 10 种语言(src/i18n/config.ts):en、es、fr、de、it、nl、ko、pt-BR、zh-CN、zh-TW。默认 en。
  • 7 个命名空间:common、launch、editor、timeline、settings、dialogs、shortcuts。
  • 文件位于 src/i18n/locales/<locale>/<namespace>.json。
  • 用法:src/contexts/I18nContext.tsx 提供 useI18n(),取词形如 t("app.editorTitle", "Recordly Editor") —— 第二个参数是兜底文案。
  • 校验:npm run i18n:check(scripts/i18n-check.mjs)。CI 里目前是 advisory(不阻塞),因为 main 上有已知的语言对齐欠账。
  • 翻译规范见仓库根目录的 TRANSLATION_GUIDE.md;有自动翻译工作流 .github/workflows/auto-translate-zh.yml。
新增文案请同时补 en 和 zh-CN,否则 i18n:check 会报差集。

12. 测试

npm test          # vitest --run(单次)
npm run test:watch

配置要点(vitest.config.ts):

  • environment: "node" —— 没有 DOM。要测组件得自己 mock 或在该文件加 environment 覆盖。
  • globals: true,可直接用 describe / it / expect。
  • include:src/** 与 electron/** 下的 *.{test,spec}.*。
  • @ 别名已配。

测试分布(共 134 个文件):

区域文件数覆盖内容
src/lib/exporter/27编码、音轨路由、帧渲染、封装、比特率、保存策略(最密集)
electron/38权限、导航、GPU 开关、窗口边界、媒体服务、录制各平台实现、项目原子保存、字幕与 ffmpeg
src/components/video-editor/timeline/12时间线 core 纯函数、DnD 引擎、键盘快捷键、范围、选择、布局
src/components/video-editor/videoPlayback/—缩放变换、光标跟随 / 缩放 / 摇摆、场景动效、webcam 同步
src/components/video-editor/—片段切分 / 变速 / 跨度、字幕操作、历史记录、项目脏态与持久化
src/lib/—公告、壁纸、资源路径、媒体时间、pixi 生命周期
约定:易碎逻辑必须有测试。 现有代码里 hudMousePassthrough、cursorScale、audioResourceVersion 这类一看就容易错的文件都配了测试,新增同类逻辑请照做。

13. 代码规范

用 Biome(不是 ESLint + Prettier)。

npm run lint         # biome lint .
npm run lint:fix
npm run format       # biome format --write .
npm run format:check
npx tsc --noEmit     # 类型检查(构建脚本里是 npx tsc)

格式化约定(biome.json):

  • 缩进 Tab(indentStyle: "tab",indentWidth: 4)
  • 行宽 100,换行符 LF,字符串 双引号
  • 自动整理 import(assist.actions.source.organizeImports: "on")

Lint 特点:

  • 没有启用 recommended 预设,每条规则显式列出 —— 想加规则要显式写。
  • noExplicitAny: error、noNonNullAssertedOptionalChain: error、noTsIgnore: error:不要用 any 和 @ts-ignore 走捷径。
  • useExhaustiveDependencies 是 warn,但 useHookAtTopLevel、noUnusedVariables 是 error。
  • 忽略 dist、dist-electron、release、.tmp、electron/native/**/build。

TypeScript(tsconfig.json):strict: true、noUnusedLocals、noUnusedParameters、noFallthroughCasesInSwitch,且排除测试文件(测试由 Vitest 负责)。


14. 环境变量与调试开关

变量作用
VITE_DEV_SERVER_URL由 vite-plugin-electron 注入。有值即 dev:userData 切到 Recordly-dev、跳过单实例锁
RECORDLY_SMOKE_EXPORT=1启动即进入编辑器冒烟导出,并打印 GPU 特性诊断
RECORDLY_SMOKE_EXPORT_INPUT冒烟导出的输入文件路径
RECORDLY_SMOKE_EXPORT_PROJECT冒烟导出的输入项目文件(优先于上一项)
RECORDLY_DEV_OPEN_RECORDING_INPUT启动后直接打开指定录像进编辑器
RECORDLY_DEV_PREVIEW_UPDATE=1dev 下预览更新提示 UI(macOS 走 toast,其他平台走原生对话框)
WHISPER_RUNTIME_ARCHSall / arm64 / x64,控制 whisper 编译目标架构
WHISPER_RUNTIME_ALLOW_MISSING=1缺 CMake 时不报错,直接没有字幕能力
CI=true让 whisper 缺 CMake 变成软失败(同时会影响其他脚本行为)
PACKAGED_SMOKE_ARCH_TAGS打包冒烟测试指定架构标签(CI 传 darwin-x64 / darwin-arm64)

15. 打包与发布

npm run build:win      # NSIS 安装包
npm run build:mac      # dmg + zip(x64 / arm64)
npm run build:linux    # AppImage

相关脚本:

脚本用途
smoke:packaged-binaries校验打包产物中的原生二进制是否齐全
smoke:electron-main-cjs校验主进程产物是合法 CJS
normalize:electron-main-cjs产物规整
verify:macos-distributionmacOS 分发校验
checksums:release生成 SHA256 校验和文件
release:create创建 Release

发布流程的权威说明在 RELEASING.md,请以它为准。

GitHub Actions 流水线:

工作流触发作用
quality.ymlPR / push main质量门禁(见下节)
build.yml手动三平台构建 + 冒烟 + 校验和 + attest + 上传 artifact
release.yml—正式发布
winget-releaser.yml—发布到 winget
homebrew-tap.yml—更新 Homebrew tap(recordly.rb)
macos-release-candidate.yml—macOS RC
auto-translate-zh.yml—中文翻译自动化

16. CI 质量门禁

quality.yml 在 PR 与 push main 时执行(ubuntu,20 分钟超时):

步骤命令是否阻塞
安装依赖npm ci --ignore-scripts阻塞(注意跳过原生编译)
类型检查npx tsc --noEmit阻塞
Lintnpm run lint阻塞
格式检查npm run format:checkadvisory(continue-on-error)
测试npm test阻塞
翻译校验npm run i18n:checkadvisory

提 PR 前本地跑这三条就够:

npx tsc --noEmit && npm run lint && npm test

17. 常见问题

npm install 失败 / 卡在 postinstall
先看失败在哪一步。postinstall 分两段:rebuild:native 和 build:platform-native-helpers,日志里都有 [postinstall] Running npm script: xxx 前缀。
如果只是改前端,用第 3 节的 --ignore-scripts 方案绕开。

uiohook-napi 运行时崩溃 / ABI 不匹配
npm run rebuild:native(等价于 electron-rebuild --force --only uiohook-napi)。

没有 CMake,字幕功能不可用
Windows x64 通常会走预编译,不会遇到;其他情况装 CMake(含 VS 的 CMake 组件)后执行 npm run build:whisper-runtime。
想先跳过:WHISPER_RUNTIME_ALLOW_MISSING=1。

打包后 ffmpeg / 原生辅助程序找不到

  1. 确认它们在 asarUnpack 列表里;
  2. 跑 npm run smoke:packaged-binaries 定位缺哪个。

本地有日志、打包装没有
terser 的 drop_console 把 console.log / console.debug 删了,属预期行为。

Windows 摄像头 / 麦克风不工作
主进程启动时会打印 [permissions] Camera access is "..." 警告。去「设置 → 隐私和安全性 → 相机 / 麦克风」开启。

macOS 录制失败或光标不动
需要 屏幕录制 与 辅助功能 权限。应用内有跳转按钮(openScreenRecordingPreferences / openAccessibilityPreferences)。本地构建若被隔离:xattr -rd com.apple.quarantine /Applications/Recordly.app。

Linux 编译报 X11 头文件缺失
装 .github/workflows/build.yml 里那一串:libx11-dev libxt-dev libxtst-dev libxkbfile-dev libxi-dev libxrandr-dev libxinerama-dev。

Linux 屏幕共享弹两次选择框 / 托盘点了没反应
Wayland 已知问题,处理逻辑在 main.ts 与 setDisplayMediaRequestHandler 里,改这块前先读完相关注释。

改了 windowType 相关代码后行为异常
回顾第 6 节:主进程靠 URL 里的 windowType=editor 判断窗口身份。

Vite 构建时抛 Electron main CJS smoke failed
构建守卫生效了,跑 npm run smoke:electron-main-cjs 看具体原因,通常是主进程被打成了 ESM。


18. 贡献流程

  1. 从 main 切分支(仓库默认分支是 main,别用 master)。
  2. 按第 13 节的规范写代码,按第 12 节的习惯补测试。
  3. 本地过一遍:npx tsc --noEmit && npm run lint && npm test。
  4. 提 PR,遵循 .github/pull_request_template.md。
  5. CI 会跑质量门禁;仓库配置了 CodeRabbit(.coderabbit.yaml)做自动评审,其评审指令在 .github/instructions/general.instructions.md(要求:不打行内评论,只给一条汇总,含等级 A-F、阻塞问题、可选改进、是否可合并)。
  6. Issue 模板:.github/ISSUE_TEMPLATE/bug_report.yml、feature_request.yml。

扩展开发:Recordly 有社区扩展系统(光标点击音效、设备边框、浏览器外壳、壁纸、渲染钩子、设置面板等),接口说明见 EXTENSIONS.md,市场在 https://marketplace.recordly.dev/extensions。


附:改动速查表

你想改什么先从哪个文件入手
HUD 按钮 / 录制控制src/components/launch/LaunchWindow.tsx、RecordingControls.tsx
录制参数(麦克风、系统音频)electron/ipc/recording/ + electron/ipc/settings/recordingPreferencesStore.ts
时间线拖拽行为src/components/video-editor/timeline/engine(timeline/dnd/engine.ts)与 timeline/core/
导出画质 / 码率src/lib/exporter/exportBitrate.ts、exportTuning.ts、backendPolicy.ts
导出后端选择src/components/video-editor/export/ + electron/ipc/export/native-video.ts
光标外观 / 跟随src/components/video-editor/videoPlayback/cursor*.ts
自动字幕electron/ipc/captions/(whisper + 分段 + 静音检测)
新增一个 IPCelectron/ipc/register/* → preload.ts → electron-env.d.ts
新增窗口electron/windows.ts + src/App.tsx 的 windowType 分支
加界面文案src/i18n/locales/{en,zh-CN}/*.json
原生辅助程序electron/native/ + scripts/build-*.mjs
打包产物内容electron-builder.json5
DISCUSSION

评论

登录后参与
请使用网站前台用户账号登录后发表评论。

正在加载评论...


返回列表返回资讯列表

作者信息

超级管理
超级管理
等级作者
155文章
0点赞
0收藏
查看作者其他文章
广告🧩

软件定制 · 企业级项目 8 折起

10 年经验团队,按需定制 CRM、ERP、小程序,合同保障。

DDevStudio查看案例 →

文章展示

公众号排版助手上线|Markdown一键排版,直推草稿箱 - 东营码良软件开发资讯公众号排版助手上线|Markdown一键排版,直推草稿箱小程序UI设计有哪些风格?8种主流界面风格与5类导航图标设计指南 - 东营码良软件开发资讯小程序UI设计有哪些风格?8种主流界面风格与5类导航图标设计指南项目逆向研发|科研 - 东营码良软件开发资讯项目逆向研发|科研破甲软件下载 - 东营码良软件开发资讯破甲软件下载一个小项目养活一家人|纯干货无偿分享 - 东营码良软件开发资讯一个小项目养活一家人|纯干货无偿分享

热门排行

如何开通微信虚拟支付功能? - 东营码良软件开发资讯1如何开通微信虚拟支付功能?276 阅读东营网站开发哪家专业?选东营码良软件开发定制建站 - 东营码良软件开发资讯2东营网站开发哪家专业?选东营码良软件开发定制建站198 阅读如何在微信小程序中接入虚拟支付功能? - 东营码良软件开发资讯3如何在微信小程序中接入虚拟支付功能?150 阅读一个小项目养活一家人|纯干货无偿分享 - 东营码良软件开发资讯4一个小项目养活一家人|纯干货无偿分享129 阅读虚拟商品类小程序全类型汇总(2026微信合规版) - 东营码良软件开发资讯5虚拟商品类小程序全类型汇总(2026微信合规版)108 阅读团播动态灯牌MOV特效贴片定制 - 东营码良软件开发资讯6团播动态灯牌MOV特效贴片定制59 阅读
CONTENT GUIDE

文章目录

48 项
  1. 01目录
  2. 021. 技术栈
  3. 032. 环境准备
  4. 04通用
  5. 05各平台额外依赖
  6. 06系统版本下限
  7. 073. 快速开始
  8. 08npm install 到底做了什么
  9. 09只想改前端、不想编译原生代码
  10. 10开发模式的一个关键点
  11. 114. 目录结构
  12. 125. 构建流水线
  13. 135.1 dev 与 build 的区别
  14. 145.2 主进程为什么强制 CJS
  15. 155.3 字幕(whisper)运行时
  16. 165.4 生产构建的两个坑
  17. 175.5 打包配置要点(electron-builder.json5)
  18. 186. 多窗口体系
  19. 19平台差异(都是踩过的坑,注释里写得很细)
  20. 20关闭编辑器的行为
  21. 217. IPC 架构与安全策略
  22. 227.1 桥的形态
  23. 237.2 主进程侧的注册方式
  24. 247.3 安全策略(三道闸)
  25. 258. 原生层
  26. 26macOS(Swift,只在 macOS 上编译)
  27. 27Windows(C++ / CMake)
  28. 28辅助程序清单(helpers-manifest)
  29. 29与主进程的衔接
  30. 309. 渲染层:录制端与编辑器
  31. 319.1 录制端(src/components/launch/)
  32. 329.2 编辑器(src/components/video-editor/)
  33. 339.3 导出引擎(src/lib/exporter/)
  34. 3410. 数据与文件位置
  35. 35userData 根目录
  36. 36目录与文件清单(electron/ipc/constants.ts)
  37. 37文件格式约定
  38. 38自动清理策略
  39. 39光标遥测
  40. 4011. 国际化
  41. 4112. 测试
  42. 4213. 代码规范
  43. 4314. 环境变量与调试开关
  44. 4415. 打包与发布
  45. 4516. CI 质量门禁
  46. 4617. 常见问题
  47. 4718. 贡献流程
  48. 48附:改动速查表