改 Rust 那部分:本地 WASM 开发的四步链路
先把状态说清楚,这一段不是免责套话,是读下去的前提:
本文描述的是 OpenCut 旧版(classic)的行为。该代码库已归档、不再维护,
opencut.app线上目前仍运行该版本;重写版正在开发中,功能与操作可能变化。核对日 2026-08-09。
两个仓库长得很像但完全不是一回事。OpenCut-app/opencut-classic 是旧版,GitHub 元数据显示它 archived 为 true、最后推送停在 2026-05-17;OpenCut-app/OpenCut 是重写版主仓,README 首句就写着它正在被从头重写。下面所有命令、目录、构建步骤,全部来自 classic 那一个仓库,跟重写版没有关系。重写版 README 列的 Editor API、第三方插件、MCP server、无头模式那几条都还是计划,本文一个字都不涉及。
一、先判断:你到底需不需要这条链路
classic 的 README 把这件事说得很克制——本地 WASM 开发只有在你改 rust/wasm 且希望 web 用你的本地构建时才需要。
这句话值得展开一下,因为它直接决定了你今天要装多少东西。classic 的项目结构是四块:apps/web/ 是 Next.js web 应用,apps/desktop/ 是用 GPUI 构建的原生桌面应用(README 自己标了 in progress),rust/ 是平台无关的核心——GPU 合成器、特效、蒙版和 WASM 绑定都在这里,docs/ 放架构文档。README 还说他们正在把业务逻辑从 TypeScript 往 rust/ 迁。
所以决策路径很短:
- 只改界面、状态、面板逻辑这些 TypeScript 的部分 → 不用碰 WASM 链路,走常规的
bun install+bun dev:web就行,应用起在http://localhost:3000。 - 要碰
rust/wasm里的绑定,或者改了rust/crates/下的东西想让浏览器端用上你改完的版本 → 才需要这四步。 - 想做桌面端 → 那是另一条路。README 明确说桌面端是 opt-in 的,只做 web 就完全跳过;要做
apps/desktop得看apps/desktop/README.md,两步走,先 Rust 工具链再桌面原生依赖。
顺带说一下 rust/crates/ 里有什么,这能帮你判断改动的影响面:实读目录是六个 crate——bridge、compositor、effects、gpu、masks、time,另外还有 rust/wasm/,它发布为 npm 包 opencut-wasm。其中 gpu crate 的 Cargo.toml 里有一段 [target.'cfg(target_arch = "wasm32")'.dependencies],说明它针对 wasm32 目标有单独的依赖,也就是同一套 GPU 代码要同时服务浏览器和原生两边。这一点是从 Cargo.toml 的结构读出来的事实,具体表现如何我们没有验证过。
二、一次性前置:三条命令,各管各的
README 给的前置是这三条:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # Rust 工具链
cargo install wasm-pack # 构建 WASM 包
cargo install cargo-watch # 供 bun dev:wasm 监听文件变化
一条条说为什么在这:
第一条装 Rust 工具链,装完才有 cargo,后两条才跑得起来。要注意这是 Unix shell 形式的管道安装脚本,我们在 classic README 的这一段里没有见到 Windows 侧 rustup 的对应写法,请以 rustup 官网的说明为准,别把这行直接贴进 PowerShell。
第二条 wasm-pack,README 给的用途是「构建 WASM 包」,第 1 步 build:wasm 要靠它才有得跑;至于这个脚本内部具体怎么调用它,我们没有逐行核对过 package.json 里的脚本定义,不下断言。
第三条 cargo-watch 的用途 README 写得很直白:供 bun dev:wasm 监听文件变化。换句话说,只跑一次构建的话它不是必需的,但你要的是「改完 Rust 保存自动重建」这个体验,就得先有它。少装这一条,前三步用不到它、看起来一路顺,到第 4 步才会缺依赖——这是最容易漏的一个坑。具体会报什么错我们没跑过,不编。
另外别忘了 classic 的通用前置:Bun 和 Docker / Docker Compose。README 注明 Docker 是可选但推荐的,用来跑本地数据库和 Redis,只做前端可以跳过。环境变量文件要先复制:
cp apps/web/.env.example apps/web/.env.local # Unix/Linux/Mac
Copy-Item apps/web/.env.example apps/web/.env.local # Windows PowerShell
README 说 .env.example 的默认值与 Docker Compose 配置对应,是开箱即用的。
三、四步链路本身
bun run build:wasm # 1. 从仓库根构建一次
cd rust/wasm/pkg && bun link # 2. 注册生成的包
cd apps/web && bun link opencut-wasm # 3. 把 apps/web 链到本地包
bun dev:wasm # 4. 改动时重新构建
以上命令原样抄自 classic README,我们没有执行过其中任何一条。
这四步的逻辑串起来是这样的:第 1 步在仓库根跑构建,把 Rust 代码编成 WASM 包,产物落在 rust/wasm/pkg——这个路径不是猜的,第 2 步的 cd rust/wasm/pkg 就是证据。第 2 步在产物目录里注册这个本地包,第 3 步在 apps/web 里把依赖指向刚注册的那个本地包,名字是 opencut-wasm。第 4 步进入监听模式,之后你改 Rust,它负责重建。
第 2、3 步是包管理器的本地链接机制,属于 npm / bun 生态的通用做法,不是 OpenCut 特有的设计。它解决的问题是:apps/web 的依赖里本来写着 opencut-wasm,正常情况下会去装发布出来的那个版本;链接之后,同一个名字被指向你本地刚构建出来的目录,于是 web 端加载的就是你的改动。这一步必须做两次(一次注册、一次消费)是 link 类命令的常见形态,漏掉任何一次,web 端拿到的都还是原来那份。
四、产出物长什么样
只写有依据的部分,别的不编:
- 构建产物目录:
rust/wasm/pkg。这是命令里明写的路径。 - 包名:
opencut-wasm,第 3 步bun link opencut-wasm用的就是它,它同时也出现在apps/web/package.json的依赖清单里,是那份清单里唯一一个 Rust 编译出来的核心包。 - 按链接机制推断:
pkg目录里应当存在一个package.json,其name字段就是opencut-wasm,否则第 3 步按名字匹配无从下手。这一条是从命令语义推出来的,README 没有逐个列出pkg目录下有哪些文件,我们也没有构建过,所以只当作合理预期,不当作事实。 - 执行结果:命令失败会以非零码退出,这是 shell 的通用约定。具体会打印什么日志行、什么提示文案,我们没有跑过,不编造。
五、怎么验收
按顺序卡这几个点,出问题基本都在其中之一:
- 前置装全没有。
cargo能不能调用、wasm-pack和cargo-watch有没有装上。这三个是后面所有步骤的地基。特别是cargo-watch——前三步不用它,所以你可能一路顺到第 4 步才发现漏了。 - 第 1 步是不是在仓库根跑的。README 写的是「从仓库根构建一次」,在子目录里跑脚本名可能压根找不到。
rust/wasm/pkg是不是真的生成了。第 2 步要cd进去,目录不存在就说明第 1 步其实没成功,别急着往下走。- 两次 link 是不是都做了。第 2 步在
rust/wasm/pkg里,第 3 步在apps/web里,两个目录不一样,注意每步前面的cd。只做第 2 步不做第 3 步,是最典型的「命令全跑完了但 web 端没变化」。 - 改完 Rust 之后
bun dev:wasm有没有在跑。它是负责重建的那一环,不开着的话你改了也不会自动生效。
一个额外的提醒:web 端的开发服务(bun dev:web,起在 http://localhost:3000)和 WASM 的监听重建是两件事,要分开看。WASM 重建完成不等于浏览器那侧已经拿到新的产物,这中间还隔着前端的模块加载与缓存。我们没有跑过这套流程,所以这里只提醒你把两条链路分开排查,不给具体结论。
六、什么情况不适用
- 你只改 TypeScript。这是最重要的一条。classic 的特效体系里,TypeScript 和 Rust 的分工边界是写在
docs/effects-renderer.md里的:TypeScript 决定跑哪些 shader 标识符、传哪些 uniform,Rust/wgpu 拥有设备创建、纹理和 pass 执行。所以像新增一个特效定义这种事——在apps/web/src/lib/effects/definitions/建文件、导出一个EffectDefinition、在同目录index.ts注册——落点全在 TypeScript 侧,不需要重新编 WASM。 - 你只是想跑起来看看。那就用发布出来的
opencut-wasm依赖,走常规bun install,别给自己加一整套 Rust 工具链。 - 你在 Windows 上,还没确认 rustup 的安装方式。README 这一段给的是 Unix 形式的命令,先去 rustup 官网确认 Windows 侧怎么装,不要照抄。
- 你打算基于这套流程做长期维护。classic 已经归档、不再接受提交与 issue。代码是 MIT 许可,仍然可以 fork 自行维护,但你得清楚上游不会再动了。至于重写版什么时候接管,官方 README 只说「直到它准备好」,没有给时间表,我们也不做预测。
最后补一句立场归属:classic README 给的三条「Why」——Privacy(视频留在你自己设备上)、Free features(CapCut 的多数基础功能现在被收进付费墙)、Simple(人们想要好用的编辑器,CapCut 证明了这一点)——这是项目方自己的主张,不是我们的评价,我们也不对任何商业产品的收费策略作判断。不过第一条主张和技术选型确实对得上:依赖清单里既有 opencut-wasm 这个 Rust 编译的核心,也有媒体处理库 mediabunny,方向上指向媒体与渲染的重活在浏览器本地完成。这是从依赖清单读出的用途方向,具体功能表现我们没有验证。
延伸阅读
本文依据 OpenCut 官方仓库(github.com/OpenCut-app/OpenCut 与已归档的 github.com/OpenCut-app/opencut-classic)的 README、docs/ 架构文档、package.json、Cargo.toml 与 changelog/ 整理,核对日 2026-08-09。本文内容为仓库源码与文档口径,我们没有编译或运行过任何版本的 OpenCut。
本文描述的是 OpenCut 旧版(classic)的行为。该代码库已归档、不再维护,
opencut.app线上目前仍运行该版本;重写版正在开发中,功能与操作可能变化。
许可条款请以官方 LICENSE 原文为准,本文不构成法律意见。