预加载 WASM
渲染 Rive 实例时,你的浏览器会发出网络请求到 https://unpkg.com/@rive-app/[email protected]/rive.wasm,该请求会获取一个 Web Assembly (WASM) 文件,其中包含用于构建渲染循环的 Rive 特定 API。unkpg 是一个全球 CDN,可以快速加载 NPM 包,在此情况下包括 WASM 文件。这使得在引入 Rive 基于 JS 的运行时时包体积更小,而只有在创建 Rive 实例时才加载 WASM。
自托管 Rive WASM
虽然 unpkg 应能快速提 供 WASM,但你可能希望将 WASM 文件作为同源静态资源自行预加载和托管,原因包括:
- 严格掌控驱动 Rive 动画的 WASM 来源,而非依赖第三方 unpkg CDN
- 更快地初始化 Rive
- 能够控制
rive.wasm文件的缓存策略
如果你确实决定自行托管 WASM 文件,请注意以下几点:
rive.wasm文件的版本必须与 package.json 中的@rive-app包版本匹配——它们是成对构建的,版本不匹配会导致运行时渲染或功能异常。将版本号放在路径或文件名中(例如rive-2.38.5.wasm),并在更新依赖的同一提交中更新托管的文件。<link rel="preload">的 href 与传给setWasmUrl()的 URL 必须完全一致,否则预加载的字节会被丢弃,文件会被下载两次。参见下面的示例。- 以
application/wasmMIME 类型提供该文件——其他类型会让你脱离流式编译路径,降级到更慢的回退方案。 - 如果文件与页面位于不同源(例如 CDN 子域名),还需为你的页面源发送
Access-Control-Allow-Origin。 - 以
Cache-Control: public, max-age=31536000, immutable提供带版本的文件,并确认你的 CDN 对 .wasm 应用了 brotli/gzip 压缩(某些 CDN 默认只压缩文本类型)。
在页面加载时初始化 Rive
如果你需要 Rive 在页面加载时立即可用于渲染图形(例如 hero 动画),我们建议同时预加载 rive.wasm 文件 和实际的 .riv 文件,以便浏览器提前开始下载必要资源。在 JS 端,你可以使用 RuntimeLoader API 在页面上实例化 Rive 图形之前,提前开始下载并编译 WASM。另一个优化是提前 fetch .riv 文件并以 ArrayBuffer 形式获取字节,以便传递给 Rive 实例。
<!-- index.html -->
<!-- 尽早打开到 wasm CDN 的连接 -->
<!-- 如果你自行托管 WASM 文件,请将此处改为你的 CDN URL -->
<link rel="preconnect" href="https://unpkg.com" crossorigin />
<!-- 预加载运行时将请求的精确带版本 wasm URL。
版本必须与已安装的 @rive-app 包版本匹配,否则
运行时会重新拉取该资源 -->
<!-- 如果你自行托管 WASM 文件,请将此处改为你服务器上 rive.wasm 的位置 -->
<link
rel="preload"
as="fetch"
crossorigin
href="https://unpkg.com/@rive-app/[email protected]/rive.wasm"
/>
<!-- 同时预加载主要的 hero .riv 文件 -->
<link rel="preload" as="fetch" crossorigin href="/assets/hero.riv" />
import { Rive, RuntimeLoader } from '@rive-app/canvas';
// (可选)仅当你在自己的服务器上托管 WASM 文件时才需要添加
// const WASM_URL = "https://cdn.example.com/assets/rive-2.38.5.wasm";
// RuntimeLoader.setWasmUrl(WASM_URL);
// 在页面加载时尽可能早地运行此 API,以开始编译 rive.wasm 文件
RuntimeLoader.awaitInstance().catch(() => {});
const heroFetch = fetch("/assets/hero.riv").then((r) => r.arrayBuffer());
// ... 稍后,在挂载时:
async function mountHero(canvas) {
const riveInstance = new Rive({
canvas,
buffer: await heroFetch,
stateMachines: "State Machine 1",
autoBind: true,
autoplay: true,
// ... 其他配置
});
}
特别鸣谢
特别感谢 Alex Barashkov 的原始博客文章启发了我们添加此技巧。
https://dev.to/alex_barashkov/optimization-techniques-for-rive-animations-in-react-apps-1a8p