From b942e9156bd8dfccff6bbf60bdfb3c132b13564f Mon Sep 17 00:00:00 2001 From: Johnathon Selstad Date: Thu, 24 Jul 2025 15:39:58 -0700 Subject: [PATCH 1/3] Add Emscripten Instructions and Gotchas I spent two days figuring out how to get Emscripten WASM modules working in PartyKit, assembled from old Discord messages and abandoned example repos with out-dated WASM import mechanisms. The instructions here represent the cleanest and most useful way to get Emscripten modules working in Cloudflare Workers and Durable Objects. --- .../runtime-apis/webassembly/javascript.mdx | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/content/docs/workers/runtime-apis/webassembly/javascript.mdx b/src/content/docs/workers/runtime-apis/webassembly/javascript.mdx index ab9fb6a74020f0..9836767c5e9692 100644 --- a/src/content/docs/workers/runtime-apis/webassembly/javascript.mdx +++ b/src/content/docs/workers/runtime-apis/webassembly/javascript.mdx @@ -83,6 +83,31 @@ export default { When invoked, this Worker should log `Hello from JavaScript: 42` and return `Success: 42`, demonstrating the ability to invoke Wasm methods with arguments from JavaScript and vice versa. +## Use of Emscripten Modules from Javascript + +WebAssembly modules compiled with Emscripten require a few considerations for use with Workers. Specifically, they should be compiled with `MODULARIZE=1`, `EXPORT_ES6=1`, `ENVIRONMENT=web`, and `DYNAMIC_EXECUTION=0` to avoid the workers' limitations with nodejs compatibility and dynamic code execution. + +Then, the module can be instantiated in your worker with: +```javascript +import { M } from './myModule.js'; +import mod from './myModule.wasm'; +/** @typedef {import("./myModule.js").MyModuleToplevel} MyModuleToplevel */ + +async initializeMyModule() { + /** @type {MyModuleToplevel} */ + var myModule = await M({ + instantiateWasm: (imports, callback) => { + const instance = new WebAssembly.Instance(mod, imports); + callback(instance); + return instance.exports; + } + }); +} +initializeMyModule(); +``` + +Please refer to [this example](https://github.com/cloudflare/worker-emscripten-template) for details. + ## Next steps In practice, you will likely compile a language of your choice (such as Rust) to WebAssembly binaries. Many languages provide a `bindgen` to simplify the interaction between JavaScript and Wasm. These tools may integrate with your JavaScript bundler, and provide an API other than the WebAssembly API for initializing and invoking your Wasm module. As an example, refer to the [Rust `wasm-bindgen` documentation](https://rustwasm.github.io/wasm-bindgen/examples/without-a-bundler.html). From d6b20c4fd08862fd5036438b37f84233b9b09c4b Mon Sep 17 00:00:00 2001 From: Johnathon Selstad Date: Thu, 24 Jul 2025 15:49:32 -0700 Subject: [PATCH 2/3] Apply suggestions from code review Add Suggestions from Github Actions Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../docs/workers/runtime-apis/webassembly/javascript.mdx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/content/docs/workers/runtime-apis/webassembly/javascript.mdx b/src/content/docs/workers/runtime-apis/webassembly/javascript.mdx index 9836767c5e9692..5cee2fc56342d6 100644 --- a/src/content/docs/workers/runtime-apis/webassembly/javascript.mdx +++ b/src/content/docs/workers/runtime-apis/webassembly/javascript.mdx @@ -93,9 +93,9 @@ import { M } from './myModule.js'; import mod from './myModule.wasm'; /** @typedef {import("./myModule.js").MyModuleToplevel} MyModuleToplevel */ -async initializeMyModule() { +async function initializeMyModule() { /** @type {MyModuleToplevel} */ - var myModule = await M({ + const myModule = await M({ instantiateWasm: (imports, callback) => { const instance = new WebAssembly.Instance(mod, imports); callback(instance); @@ -103,7 +103,9 @@ async initializeMyModule() { } }); } -initializeMyModule(); +initializeMyModule().catch(error => { + console.error("Failed to initialize the module:", error); +}); ``` Please refer to [this example](https://github.com/cloudflare/worker-emscripten-template) for details. From ec95261546b065567d5addfe65f5b8be55a8edb4 Mon Sep 17 00:00:00 2001 From: Johnathon Selstad Date: Thu, 24 Jul 2025 15:55:00 -0700 Subject: [PATCH 3/3] Update javascript.mdx Switch from async/await to then/catch syntax to be called from the top level. --- .../runtime-apis/webassembly/javascript.mdx | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/content/docs/workers/runtime-apis/webassembly/javascript.mdx b/src/content/docs/workers/runtime-apis/webassembly/javascript.mdx index 5cee2fc56342d6..b3e474c72fab66 100644 --- a/src/content/docs/workers/runtime-apis/webassembly/javascript.mdx +++ b/src/content/docs/workers/runtime-apis/webassembly/javascript.mdx @@ -87,23 +87,22 @@ When invoked, this Worker should log `Hello from JavaScript: 42` and return `Suc WebAssembly modules compiled with Emscripten require a few considerations for use with Workers. Specifically, they should be compiled with `MODULARIZE=1`, `EXPORT_ES6=1`, `ENVIRONMENT=web`, and `DYNAMIC_EXECUTION=0` to avoid the workers' limitations with nodejs compatibility and dynamic code execution. -Then, the module can be instantiated in your worker with: +Then, the module can be instantiated in your Worker with: ```javascript import { M } from './myModule.js'; import mod from './myModule.wasm'; /** @typedef {import("./myModule.js").MyModuleToplevel} MyModuleToplevel */ -async function initializeMyModule() { +M({ + instantiateWasm: (imports, callback) => { + const instance = new WebAssembly.Instance(mod, imports); + callback(instance); + return instance.exports; + } +}).then(instantiatedModule => { /** @type {MyModuleToplevel} */ - const myModule = await M({ - instantiateWasm: (imports, callback) => { - const instance = new WebAssembly.Instance(mod, imports); - callback(instance); - return instance.exports; - } - }); -} -initializeMyModule().catch(error => { + const myModule = instantiatedModule; +}).catch(error => { console.error("Failed to initialize the module:", error); }); ```