Motrix 贡献者指南:开发环境搭建、分层架构边界与提交前验证门禁
【免费下载链接】MotrixA full-featured download manager.项目地址: https://gitcode.com/GitHub_Trending/mo/Motrix
本文以 Motrix 仓库的 CONTRIBUTING.md 为主体,完整还原参与该开源下载管理器的全流程:从开发环境搭建(Git、Node.js 22+、pnpm 版本锁定)、独立用户数据目录的 dev 运行时,到 renderer/main/server/core/shared 分层架构与传输协议约定,再到提交前必须通过的check:boundaries、lint、类型检查等验证门禁与分支/提交/PR 规范。读完后你可以独立完成一次符合项目标准的贡献提交,并理解其架构约束在源码层面如何被自动检查强制落地。
选择正确的贡献渠道
Motrix 接受代码、测试、文档、翻译、issue 报告和设计反馈等多种形式的贡献。在提交之前,项目明确要求:
- 创建新报告前,先检索已打开和已关闭的 issues,避免重复;
- 可复现的 bug 和聚焦的功能请求使用仓库的 issue 表单;
- 支持类问题、使用指导以及尚未成熟的想法,应放到 GitHub Discussions 而非 issue;
- 重大功能、架构变更、新依赖和破坏性变更,需要先讨论再投入实现;
- 每个 issue 和 PR 只聚焦一个问题或一项能力。
参与本项目受 行为准则 约束;疑似安全漏洞必须按 安全策略 私下报告,严禁在公开的 issue、讨论或 PR 中披露。
准备开发环境
工具链与版本锁定
开发需要 Git、Node.js 22 或更高版本,以及package.json中packageManager字段声明的 pnpm 版本。查看 package.json 可知当前锁定为pnpm@11.22.0,建议通过corepack或pnpm self-update对齐该版本,避免锁文件协议不一致导致的安装差异。
克隆、安装与启动
没有写权限时先 Fork 仓库,然后克隆自己的 fork 并安装依赖:
git clone https://github.com/<your-account>/Motrix.git cd Motrix pnpm install pnpm startpnpm start并非直接拉起 Electron。查看 package.json 中的脚本链可以发现,start前会执行prestart,即ensure:electron-runtime加 scripts/ensure-native-abi.mjs(针对 electron 目标重建better-sqlite3等原生模块的 ABI),随后由 scripts/dev.mjs 接管整个开发运行时。从 dev.mjs 的头部注释可以看到它的职责:
- 先通过
pnpm run build:builtin把内置插件打包到dist/builtin-plugins(源码注释明确指出:缺失该目录时 bilibili/youtube 链接会退化为普通 HTTP 下载); - 在固定端口(默认 5173,可用
VITE_DEV_PORT覆盖)启动 renderer 的 Vite dev server; - 以 watch 模式构建 main 和 preload 两份 bundle,两者首次产出后才注入
VITE_DEV_SERVER_URL启动 Electron; - 后续 main/preload 重新构建后自动重启 Electron,renderer 侧热更新由 Vite HMR 完成,无需重启。
用户数据目录隔离:dev 不污染正式版数据
文档说明pnpm start默认使用独立的用户数据目录(通常是Motrix-dev)。这一行为的确切实现在 src/main/platform/services.ts:
const isDev = !app.isPackaged const userDataOverride = process.env.MOTRIX_USER_DATA const defaultUserDataDir = app.getPath('userData') const userDataDir = userDataOverride || (isDev ? `${defaultUserDataDir}-dev` : defaultUserDataDir)即:开发态下目录在默认 userData 路径后追加-dev后缀。若要指定其他目录,在运行pnpm start前设置MOTRIX_USER_DATA为绝对路径即可;src/main/platform/services.test.ts 中的测试证实了相关契约:
MOTRIX_USER_DATA在开发态优先于-dev默认值;- 空字符串值会被忽略,回落到默认行为;
- 打包后(非开发态)的
MOTRIX_USER_DATA同样生效; - 相对路径会在创建目录前被直接拒绝,抛出
MOTRIX_USER_DATA must be an absolute path。
此外,dev 模式还会把extra资源目录解析为项目根下的extra/(如 extra/aria2.conf),打包后则来自process.resourcesPath/extra。
分支策略与分支命名
- 开发分支必须基于最新的
main创建,PR 也以main为目标; - 遗留的
master分支只保留 v1 代码库且已冻结,不要向它提交任何新变更; - 分支名格式为
<type>/<snake_case_topic>_<YYYYMMDD>,有对应 issue 时可在主题前加 issue 编号,例如fix/1970_conduct_links_20260826。
理解分层架构
Motrix Turbo 在两个应用外壳(Electron 桌面应用与 Node/Web 服务器)背后共享一个宿主无关(host-neutral)的产品核心,同一套 renderer 代码在两种宿主中运行。这种分离保证产品行为可复用、Electron 关注点不会泄漏进服务端,并允许下载引擎在稳定适配器之后被替换。
各层职责与依赖边界
| 目录 | 职责 | 依赖边界 |
|---|---|---|
| src/renderer/ | 共享的 Electron/浏览器用户界面 | 只导入@shared/和 renderer 本地模块;产品行为统一经@renderer/lib/transport访问 |
| src/preload/ | 狭窄的 Electron context bridge | 使用 Electron 和src/shared/中的纯协议值/类型,不含产品行为 |
| src/main/ | Electron 外壳、IPC、窗口、菜单与系统集成 | 可组合src/core/、src/shared/和 Electron 特定适配器 |
| src/server/ | Node/Docker 外壳、HTTP/WebSocket 端点与服务端平台集成 | 可组合src/core/、src/shared/与服务端库;禁止导入 Electron 或src/main/ |
| src/core/ | 宿主无关的应用服务、领域行为、引擎编排与插件策略 | 可用src/shared/和宿主无关库;禁止导入任一应用外壳 |
| src/shared/ | 跨层 schema、协议常量、类型、locale 数据与纯工具 | 不得包含 I/O、定时器、网络访问、Electron API 或 Node 特定 API |
| packages/native-host/ | 供浏览器扩展配对接入的独立 Rust native-messaging 宿主 | 通过已发布的 bridge 契约通信,不依赖系统 Node.js 或 Electron |
| src/test-utils/ | 仅供测试的 fixtures 与 helpers | 严禁被生产代码导入 |
这套边界在仓库目录结构中可以一一对应:例如src/server/下是 Fastify 路由与 src/server/http/、src/server/bridge/ 等服务端实现,而src/core/下则是 download、engine、plugin、session 等宿主无关领域模块。
传输与协议流
renderer 在两种宿主下使用同一套 command、query、event 契约:
Electron: renderer -> ElectronTransport -> preload -> main IPC -> core Browser: renderer -> HttpWsTransport -> server RPC/events -> core从源码结构看,这个契约确实被物理落实:
- 传输层实现在 src/renderer/lib/transport/,
electron.ts与http-ws.ts分别对应两条链路,renderer 功能代码只应经由该模块访问产品行为,直接访问window.motrix仅限于 Electron 传输层和窄范围的平台适配器; - 通道名与 payload 契约集中在 src/shared/protocol/(
commands.ts、queries.ts、events.ts及bridge.ts),应使用Commands、Queries、Events及其Bridge*常量而非裸通道字符串。
引擎、Bridge 与插件边界
- 产品级代码面向 src/core/engine/engine-adapter.ts 中定义的
EngineAdapter接口。从源码可以看到,该接口刻意保持“引擎中立”:例如AddTorrentParams中注释说明 16 位十六进制 GID、1-based 文件索引、checkIntegrity语义等均由具体 aria2 适配器负责翻译。aria2 RPC 类型与转换逻辑留在具体 aria2 适配器内,而引擎生命周期由 src/core/engine/engine-supervisor.ts 中的EngineSupervisor独占管理。 - MDXP 协议基于 HTTP 与 WebSocket 上的 JSON-RPC 2.0。
@motrix/mdxp包(见 package.json 依赖@motrix/mdxp@^0.5.0)是 wire schema、方法常量、错误码与连接行为的唯一事实来源,不得在本地重复实现这些契约。 - 宿主无关的插件状态、策略、安装、能力与沙箱编排位于 src/core/plugin/;Electron 与 Node/Docker 的接线分别在 src/main/plugin/ 和 src/server/plugin/。
- 插件 guest 代码在独立的 QuickJS worker 中运行(对应
quickjs-emscripten依赖),只能通过类型化能力桥(typed capability bridge)触达宿主行为;新增宿主特定能力时,必须在两个能力宿主中都实现并测试。
边界检查的自动化落地
文档要求:任何导入或层职责变化时都运行pnpm run check:boundaries。该脚本对应 scripts/check-boundaries.mjs,其规则表(L4-L52)正是上述架构边界的机械化表达,例如:
core must not import electron:src/core/内禁止from 'electron';core must not import fastify:src/core/内禁止 fastify 导入;shared must not use Node-specific APIs or globals:src/shared/内禁止node:导入、动态import('node:...')、process.与NodeJS.命名空间;renderer must not import core or main:src/renderer/内禁止直接导入 core/main 层;server must not import electron、server must not import src/main。
脚本通过grep -rnE逐条检查,支持按文件白名单豁免,任一条失败即以非零码退出。文档同时提醒:自动化检查只是基线,不能替代对依赖方向的人工审查。
遵循实现规范
代码与文件
- 代码、注释、标识符、文件名、commit message 与 PR 标题一律使用英文;
- JavaScript/TypeScript/TSX/样式文件使用
kebab-case命名(与仓库现状一致,如 engine-supervisor.ts、http-ws.ts); - 类型专用导入使用
import type,Node.js 内建模块使用node:前缀; - 优先使用已配置的 alias 而非深层相对导入,但需确认该 alias 在目标运行时可用;
- 行为变更必须伴随新增或更新测试;生产代码不得依赖测试 helper 或生成的构建产物。
用户可见文本与国际化
- 所有用户可见的应用与运维文本必须走既有 i18next 资源(仓库依赖
i18next与react-i18next),禁止硬编码界面字符串; - 新增或变更翻译 key 时,必须更新每一个已注册 locale,且各 locale 的占位符集合必须完全一致。从 src/shared/locales/ 可见当前注册的 locale 为
en-US.json、zh-CN.json与zh-TW.json三个; - 编辑英文/简体中文文档对中的一份时,同一变更中必须同步另一份,保持标题、命令、路径与示例对齐,同时允许各版本使用地道表达;
- 禁止提交凭据、私有 URL、个人路径、私有计划、本地生成的状态或无关变更。
提交信息
使用 Conventional Commits 格式:
<type>(<optional-scope>): <imperative summary>允许的 type 为feat、fix、refactor、perf、test、docs、chore、ci、style。summary 用小写开头、结尾不加句号、控制在 72 字符以内;动机不明显时补充 body,适用时添加BREAKING CHANGE:footer。
验证门禁
每次提交前必须运行以下三项强制门禁:
pnpm run check:boundaries pnpm run lint pnpm exec tsc --noEmit其中lint对应 package.json 的biome check .(配套lint:fix、format脚本),test对应vitest run,test:e2e对应playwright test。
然后按变更类型运行匹配的检查:
- 行为或逻辑变更:运行聚焦的 Vitest 测试;跨切面大范围改动运行
pnpm test; - 覆盖浏览器或 Electron 用户流程:
pnpm test:e2e; - locale 资源或国际化行为:
pnpm run check:i18n(实现为 scripts/check-i18n.mjs); - 新增或重命名文件:
pnpm run check:file-names(对应 scripts/check-file-names.mjs); - 插件 manifest 契约:
pnpm run check:schema-parity; - 依赖、打包资产或 license 元数据:
pnpm run check:third-party-notices; - native-host Rust 代码:运行下面一组 cargo 命令。
native-host 的验证命令(针对 packages/native-host/Cargo.toml):
cargo fmt --manifest-path packages/native-host/Cargo.toml --all -- --check cargo clippy --manifest-path packages/native-host/Cargo.toml --all-targets --locked -- -D warnings cargo test --manifest-path packages/native-host/Cargo.toml --locked --all-targets-D warnings表示 clippy 警告即失败,--locked保证不漂移Cargo.lock。最后,审查最终 diff、运行git diff --check,并在 PR 中如实记录执行过的命令与结果;不得压制失败或丢弃命令退出码。
提交 Pull Request
- 目标分支为
main,关联相关 issue,同时说明问题本身与所选方案; - 完整填写 PR 模板,包含确切的验证命令、环境与结果;
- 可见界面变更必须附截图或录屏;
- 生成文件与依赖变更严格限制在 PR 所需范围内;
- 以追加 commit 的方式回应 review 意见;维护者合并时通常会对 feature PR 做 squash。
许可证与第三方声明
贡献以仓库的 MIT License 被接受;第三方资产可能有不同条款,记录在 THIRD_PARTY_NOTICES.md 中(对应 THIRD_PARTY_LICENSES/ 下维护的各组件许可文本)。涉及依赖或许可元数据变更时,记得运行pnpm run check:third-party-notices门禁保持其同步。
【免费下载链接】MotrixA full-featured download manager.项目地址: https://gitcode.com/GitHub_Trending/mo/Motrix
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考