diff --git a/e2e/wasm/index.test.ts b/e2e/wasm/index.test.ts new file mode 100644 index 00000000..83b31e65 --- /dev/null +++ b/e2e/wasm/index.test.ts @@ -0,0 +1,9 @@ +import { expect, test } from '@rstest/core'; + +test('WASM factorial', async () => { + const { _Z4facti: AsyncFactorial } = await import('./src/factorial.wasm'); + + expect(AsyncFactorial(1)).toBe(1); + expect(AsyncFactorial(2)).toBe(2); + expect(AsyncFactorial(3)).toBe(6); +}); diff --git a/e2e/wasm/src/factorial.wasm b/e2e/wasm/src/factorial.wasm new file mode 100644 index 00000000..50ce8c09 Binary files /dev/null and b/e2e/wasm/src/factorial.wasm differ diff --git a/e2e/wasm/src/factorial.wasm.d.ts b/e2e/wasm/src/factorial.wasm.d.ts new file mode 100644 index 00000000..67641458 --- /dev/null +++ b/e2e/wasm/src/factorial.wasm.d.ts @@ -0,0 +1 @@ +export function _Z4facti(n: number): number; diff --git a/packages/core/src/core/plugins/external.ts b/packages/core/src/core/plugins/external.ts index 3f45c2d6..b915a9f7 100644 --- a/packages/core/src/core/plugins/external.ts +++ b/packages/core/src/core/plugins/external.ts @@ -15,7 +15,7 @@ const autoExternalNodeModules: ( return callback(); } - if (request.startsWith('@swc/helpers/')) { + if (request.startsWith('@swc/helpers/') || request.endsWith('.wasm')) { // @swc/helper is a special case (Load by require but resolve to esm) return callback(); } diff --git a/packages/core/src/core/plugins/mockRuntime.ts b/packages/core/src/core/plugins/mockRuntime.ts index 4276eb40..3b223502 100644 --- a/packages/core/src/core/plugins/mockRuntime.ts +++ b/packages/core/src/core/plugins/mockRuntime.ts @@ -48,6 +48,17 @@ class MockRuntimeRspackPlugin { module.source!.source = Buffer.from(finalSource); } + + if (module.name === 'async_wasm_loading') { + const finalSource = module.source!.source.toString('utf-8').replace( + // Sets the object configurable so that imported properties can be spied + // Hard coded in EJS template https://github.com/web-infra-dev/rspack/tree/7df875eb3ca3bb4bcb21836fdf4e6be1f38a057c/crates/rspack_plugin_wasm/src/runtime + 'readFile(', + 'readWasmFile(', + ); + + module.source!.source = Buffer.from(finalSource); + } }, ); }); diff --git a/packages/core/src/runtime/worker/loadModule.ts b/packages/core/src/runtime/worker/loadModule.ts index 4a24e3ba..4e329d10 100644 --- a/packages/core/src/runtime/worker/loadModule.ts +++ b/packages/core/src/runtime/worker/loadModule.ts @@ -171,6 +171,22 @@ export const loadModule = ({ assetFiles, interopDefault, ), + readWasmFile: ( + wasmPath: string, + callback: (err: Error | null, data?: Buffer) => void, + ) => { + const joinedPath = isRelativePath(wasmPath) + ? path.join(path.dirname(distPath), wasmPath) + : wasmPath; + const content = assetFiles[path.normalize(joinedPath)]; + if (content) { + callback(null, Buffer.from(content, 'utf-8')); + } else { + callback( + new Error(`WASM file ${joinedPath} not found in asset files.`), + ); + } + }, __rstest_dynamic_import__: defineRstestDynamicImport({ testPath, interopDefault, diff --git a/packages/core/src/utils/error.ts b/packages/core/src/utils/error.ts index c696bdbb..8eadca71 100644 --- a/packages/core/src/utils/error.ts +++ b/packages/core/src/utils/error.ts @@ -67,8 +67,11 @@ export async function printError( fullStack: error.fullStack, getSourcemap, }); - - if (!stackFrames.length && error.stack.length) { + if ( + !stackFrames.length && + Array.isArray(error.stack) && + error.stack.length + ) { logger.log( color.gray( "No error stack found, set 'DEBUG=rstest' to show fullStack.",