跳到主要内容

预加载 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 文件,请注意以下几点:

  1. rive.wasm 文件的版本必须与 package.json 中的 @rive-app 包版本匹配——它们是成对构建的,版本不匹配会导致运行时渲染或功能异常。将版本号放在路径或文件名中(例如 rive-2.38.5.wasm),并在更新依赖的同一提交中更新托管的文件。
  2. <link rel="preload"> 的 href 与传给 setWasmUrl() 的 URL 必须完全一致,否则预加载的字节会被丢弃,文件会被下载两次。参见下面的示例。
  3. application/wasm MIME 类型提供该文件——其他类型会让你脱离流式编译路径,降级到更慢的回退方案。
  4. 如果文件与页面位于不同源(例如 CDN 子域名),还需为你的页面源发送 Access-Control-Allow-Origin
  5. 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