Skip to content

Fix Cloudflare OG: ship .wasm as module imports, not inlined bytes#1

Open
scottmessinger wants to merge 3 commits into
mainfrom
fix/vite-wasm-bundle
Open

Fix Cloudflare OG: ship .wasm as module imports, not inlined bytes#1
scottmessinger wants to merge 3 commits into
mainfrom
fix/vite-wasm-bundle

Conversation

@scottmessinger

Copy link
Copy Markdown
Member

Problem

OG image generation fails on Cloudflare Workers with:

CompileError: WebAssembly.instantiate(): Wasm code generation disallowed by embedder

src/og.ts already does the right thing — it imports the resvg/yoga wasm as modules and calls initWasm(resvgWasm as WebAssembly.Module) / initYoga(yogaWasm). But bin/esbuild.js used loader: { ".wasm": "binary" }, which embeds each .wasm as a Uint8Array in the published dist. At runtime resvg/yoga therefore receive raw bytes and call WebAssembly.instantiate(bytes), which Cloudflare's workerd forbids (it disallows compiling wasm at runtime — only precompiled WebAssembly.Modules may be instantiated).

Fix

  • bin/esbuild.js: mark .wasm as external instead of inlining it as binary. The imports now survive into dist/index.js as real ES module imports (import … from "../vendors/*.wasm").
  • package.json: ship vendors/ alongside dist/ so those import paths resolve from the installed package.

The downstream bundler (Vite + @astrojs/cloudflare) then compiles these .wasm imports into precompiled WebAssembly.Module instances at deploy time, which workerd accepts. dist/index.js drops from ~2.2 MB to ~393 KB now that the wasm is no longer base64-inlined.

Verification

Consumed from the marketing site (Astro + @astrojs/cloudflare):

  • Prod build emits resvg.*.wasm / yoga.*.wasm as separate module files and the server chunk imports them — no inlined bytes.
  • OG route renders a valid PNG locally.

🤖 Generated with Claude Code

scottmessinger and others added 3 commits May 28, 2026 00:14
The esbuild `binary` loader embedded resvg/yoga `.wasm` as a Uint8Array in
dist. At runtime resvg/yoga then received raw bytes and called
`WebAssembly.instantiate(bytes)`, which Cloudflare's workerd forbids
("Wasm code generation disallowed by embedder").

Mark `.wasm` as external so the imports survive into dist as real ES module
imports, and ship `vendors/` alongside `dist/`. The downstream bundler
(Vite + @astrojs/cloudflare) then compiles them into precompiled
`WebAssembly.Module` instances at deploy time, which workerd accepts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 28, 2026 23:57

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes Cloudflare Workers OG image generation by switching the build from inlining .wasm files to leaving them as ES module imports that the downstream bundler can compile into precompiled WebAssembly.Module instances (required by workerd, which disallows runtime wasm compilation).

Changes:

  • bin/esbuild.js: mark .wasm as external so imports remain real ES module imports in dist/index.js instead of being copied/inlined.
  • package.json: ship vendors/ so the emitted ../vendors/*.wasm import paths resolve from the installed package, and add a prepare script so the build runs after install.

Reviewed changes

Copilot reviewed 1 out of 2 changed files in this pull request and generated no comments.

File Description
packages/workers-og/bin/esbuild.js Replaces the .wasm loader config with external: ["*.wasm"] plus an explanatory comment.
packages/workers-og/package.json Includes vendors in published files and adds a prepare script invoking pnpm build.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants