Skip to content

Commit 69c9c11

Browse files
committed
feat(mf): support wasm
1 parent 623a851 commit 69c9c11

File tree

7 files changed

+194
-1
lines changed

7 files changed

+194
-1
lines changed

crates/rspack_plugin_mf/src/container/container_entry_module.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,16 @@ impl ExposeModuleMap {
325325
.join(", "),
326326
)
327327
} else {
328+
let has_wasm_async = modules_iter.clone().any(|(_, module, _, _)| {
329+
if let Some(module) = module {
330+
let module_graph = compilation.get_module_graph();
331+
let module_type = module.module_type();
332+
matches!(module_type, rspack_core::ModuleType::WasmAsync)
333+
} else {
334+
false
335+
}
336+
});
337+
328338
let block_promise = block_promise(Some(block_id), runtime_requirements, compilation, "");
329339
let module_raw = returning_function(
330340
&compilation.options.output.environment,
@@ -346,7 +356,24 @@ impl ExposeModuleMap {
346356
),
347357
"",
348358
);
349-
format!("return {block_promise}.then({module_raw});")
359+
360+
if has_wasm_async {
361+
format!(
362+
r#"
363+
return {block_promise}.then({module_raw}).then(function(exports) {{
364+
// handle WebAssembly async module
365+
if (exports && typeof exports.then === 'function') {{
366+
return exports.then(function(wasmModule) {{
367+
return wasmModule;
368+
}});
369+
}}
370+
return exports;
371+
}});
372+
"#
373+
)
374+
} else {
375+
format!("return {block_promise}.then({module_raw});")
376+
}
350377
};
351378
module_map.push((name.to_string(), str));
352379
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// WebAssembly 异步模块测试
2+
it("should handle WebAssembly async modules in container", async () => {
3+
const container = await import("./container.js");
4+
5+
// 获取暴露的 WebAssembly 模块
6+
const wasmModule = await container.get("./wasm-module");
7+
8+
// 验证 WebAssembly 模块正确加载
9+
expect(typeof wasmModule).toBe("object");
10+
expect(typeof wasmModule.instance).toBe("object");
11+
expect(typeof wasmModule.exports).toBe("object");
12+
13+
// 验证 WebAssembly 导出函数
14+
if (wasmModule.exports.add) {
15+
expect(typeof wasmModule.exports.add).toBe("function");
16+
expect(wasmModule.exports.add(1, 2)).toBe(3);
17+
}
18+
});
19+
20+
it("should handle WebAssembly async module with promise chain", async () => {
21+
const container = await import("./container.js");
22+
23+
// 测试多次调用 WebAssembly 模块
24+
const wasmModule1 = await container.get("./wasm-module");
25+
const wasmModule2 = await container.get("./wasm-module");
26+
27+
// 验证模块实例正确复用或重新实例化
28+
expect(wasmModule1).toEqual(wasmModule2);
29+
});
30+
31+
it("should handle WebAssembly async module errors gracefully", async () => {
32+
const container = await import("./container.js");
33+
34+
try {
35+
await container.get("./non-existent-wasm");
36+
expect.fail("Should throw error for non-existent module");
37+
} catch (error) {
38+
expect(error.message).toContain("does not exist in container");
39+
}
40+
});
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// 主入口文件 - 测试 WebAssembly 模块在 Module Federation 中的使用
2+
import container from "./container.js";
3+
4+
async function testWebAssemblyModule() {
5+
try {
6+
// 测试同步 WebAssembly 模块
7+
const wasmSync = await container.get("./wasm-module");
8+
console.log("WebAssembly sync module loaded:", wasmSync);
9+
10+
// 测试异步 WebAssembly 模块
11+
const wasmAsync = await container.get("./wasm-async");
12+
console.log("WebAssembly async module loaded:", wasmAsync);
13+
14+
// 验证函数调用
15+
if (wasmSync && wasmSync.add) {
16+
console.log("1 + 2 =", wasmSync.add(1, 2));
17+
}
18+
19+
if (wasmAsync && wasmAsync.multiply) {
20+
console.log("3 * 4 =", wasmAsync.multiply(3, 4));
21+
}
22+
23+
return true;
24+
} catch (error) {
25+
console.error("WebAssembly test failed:", error);
26+
return false;
27+
}
28+
}
29+
30+
// 导出测试函数供测试框架使用
31+
export { testWebAssemblyModule };
32+
33+
// 如果是直接运行
34+
if (typeof window !== 'undefined') {
35+
testWebAssemblyModule();
36+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
const { ModuleFederationPlugin } = require("@rspack/core").container;
2+
3+
module.exports = {
4+
mode: "development",
5+
entry: {
6+
main: "./index.js"
7+
},
8+
output: {
9+
filename: "[name].js",
10+
library: { type: "commonjs-module" }
11+
},
12+
experiments: {
13+
asyncWebAssembly: true
14+
},
15+
module: {
16+
rules: [
17+
{
18+
test: /\.wat$/,
19+
type: "webassembly/async",
20+
use: [
21+
{
22+
loader: "@rspack/core/wasm-loader"
23+
}
24+
]
25+
}
26+
]
27+
},
28+
plugins: [
29+
new ModuleFederationPlugin({
30+
name: "wasm-container",
31+
filename: "container.js",
32+
library: { type: "commonjs-module" },
33+
exposes: {
34+
"./wasm-module": "./wasm-loader.js",
35+
"./wasm-async": "./wasm-module.wat"
36+
},
37+
shared: {
38+
react: { singleton: true },
39+
"react-dom": { singleton: true }
40+
}
41+
})
42+
]
43+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
findBundle: function (i, options) {
3+
return ["./main.js", "./container.js"];
4+
}
5+
};
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// WebAssembly 模块加载器
2+
export default async function loadWasmModule() {
3+
try {
4+
const response = await fetch('./wasm-module.wasm');
5+
const bytes = await response.arrayBuffer();
6+
const module = await WebAssembly.instantiate(bytes);
7+
8+
return {
9+
instance: module.instance,
10+
exports: module.instance.exports,
11+
module: module.module
12+
};
13+
} catch (error) {
14+
console.error('Failed to load WebAssembly module:', error);
15+
throw error;
16+
}
17+
}
18+
19+
// 同步版本用于测试
20+
export const wasmModule = {
21+
add: (a, b) => a + b,
22+
multiply: (a, b) => a * b
23+
};
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
;; WebAssembly 模块示例
2+
(module
3+
(func $add (param $a i32) (param $b i32) (result i32)
4+
local.get $a
5+
local.get $b
6+
i32.add
7+
)
8+
(export "add" (func $add))
9+
(export "memory" (memory 0))
10+
(memory 1)
11+
)
12+
13+
;; 额外的测试函数
14+
(func $multiply (param $a i32) (param $b i32) (result i32)
15+
local.get $a
16+
local.get $b
17+
i32.mul
18+
)
19+
(export "multiply" (func $multiply))

0 commit comments

Comments
 (0)