I am trying to build a Next JS project with an imported WebAssembly module compiled using Emscripten.
The problem seems to be related to the WebPack loader being unable to import the .wasm
module via the generated .js
.
I would greatly appreciate some help.
My C++ file hello.cpp:
#include <math.h>
extern "C" {
int int_sqrt(int x) {
return sqrt(x);
}
}
I compile using:
em++ hello.cpp -o "../v2/lib/wasm/test.js" -s MODULARIZE -s WASM=1 -s EXPORT_NAME="SZU" -s ENVIRONMENT="web" -s EXPORTED_FUNCTIONS=_int_sqrt -s EXPORTED_RUNTIME_METHODS=ccall,cwrap
I try to use the module in one of the components like so:
import SZU from "../../../../../../wasm/test";
var int_sqrt = SZU().cwrap("int_sqrt", 'number', ['number'])
When I run npx next build
the build fails with:
Error: not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)
I expect to be able to build the project using npx next build
then start the server with npx next start
and be able to interact with functions exported in the .wasm
/.js
module files generated by Emscripten.
With the help of @lab I realized my approach was wrong. This is the way I made my WASM module work:
hello.cpp
file. Important notice the extern "C" {}
block:#include <math.h>
extern "C" {
int int_sqrt(int x) {
return sqrt(x);
}
}
public
folder in next. We need to serve the .wasm
and .js
statically like @lab pointed out:em++ hello.cpp -o "../v2/public/wasm/test.js" -s MODULARIZE -s WASM=1 -s EXPORT_NAME="SZU" -s ENVIRONMENT="web" -s EXPORTED_FUNCTIONS=_int_sqrt -s EXPORTED_RUNTIME_METHODS=ccall,cwrap
next/script
tag like so:<Script src="/wasm/test.js" strategy='beforeInteractive'/>
next/useEffect
hook, wrap it with Emscripten cwrap
and store the function in a reference object using next/useRef
like so:useEffect(() => {
if(typeof (window as any).SZU === 'function' && WASM.current === null){
console.log("loading WASM!");
(window as any).SZU()
.then((wasm: WASM) => {
console.log("got WASM!");
WASM.current = wasm;
int_sqrt.current = WASM.current.cwrap("int_sqrt", "number", ["number"]);
});
}
}, []);
console.log(`Square root of 16 is ${int_sqrt.current(16)}`);
I hope this helps someone who had the same problem.