我试图用Rocket运行WebAssembly程序(用Rust编写,https://rustwasm.github.io/book/game-of-life/hello-world.html中的示例程序)。 WebAssembly是使用wasm-pack和wasm_bindgen编译的。 wasm二进制文件在Rocket中表示为content::JavaScript<Vec<u8>>
,似乎这是一个“有效”的解决方案。二进制文件已“正确”获取,但是Chrome会显示Uncaught SyntaxError:无效或意外的令牌。这是由于表示为content::JavaScript<Vec<u8>>
导致在获取期间发生错误(尽管发送字节与wasm文件中的字节匹配)还是在其他位置存在错误?
我希望有人能解释我为什么生成的二进制文件中出现SyntaxError。
答案 0 :(得分:0)
好吧,现在我想我知道出了什么问题:
从wasm-pack生成的js文件尝试将WebAssembly加载为模块。该模块需要具有Javascript哑剧,否则它将失败(这就是为什么我尝试将wasm文件作为content::JavaScript<Vec<u8>>
发送),但是显然不支持将wasm作为modul加载(如果我错了,请纠正我),因此当然,它将在二进制文件中找到无效的令牌,因为它尝试将其解释为纯JavaScript。我现在实际使用的是来自Rocket witch的Option<NamedFile>
类型的application/wasm
哑剧。
我需要稍微更改生成的js文件:WebAssembly用WebAssembly.instatiateStreaming(fetch(...), importObjects)
初始化,然后应删除模块导入。 importObjects
也有些棘手,因为将strigns传递给WebAssembly有点不方便。对于可以从WebAssembly调用的警报功能,importObjects
如下所示:
let importObjects = {'./wasm_test': { __wbg_alert_3d9cbee15c16469e: __wbg_alert_3d9cbee15c16469e }};
。
名称来自wasm二进制文件:(import "./wasm_test" "__wbg_alert_3d9cbee15c16469e" (func $__wbg_alert_3d9cbee15c16469e (type $t0)))
函数__wbg_alert_3d9cbee15c16469e
由wasm-pack生成。最后要更改的是最初通过import
语句导入的对象。我现在有一个变量,其内容来自obj.instance.exports
,该内容在WebAssembly.instatiateStreaming(fetch(...), importObjects).then(obj => {
wasm = obj.instance.exports;
})
的then语句中设置
进行了这些更改后,它为我工作(向WebAssembly发送和从WebAssembly读取字符串)
答案 1 :(得分:0)
关注Ben的回答。 .wasm
文件以application/javascript
哑剧发送,因此浏览器试图将其作为javascript执行。要与application/wasm
哑剧一起发送,请确保您的回复类型为Option<rocket::response::NamedFile>
。
这是一个例子:
#[get("/pkg/<file..>")]
fn get_pkg(file : PathBuf) -> Option<rocket::response::NamedFile> {
NamedFile::open(Path::new("client/pkg/").join(file)).ok()
}
关于第二个问题-事实证明,而不是手动编辑wasm-pack build
生成的javascript,您实际上可以要求wasm-pack
生成可以在浏览器中运行并加载wasm的javascript。简单地做
wasm-pack build --target web
。
剩下要做的就是在您这一边添加以下内容:
<script type="module">
import init from './pkg/client.js'; //client.js is the file generated by wasm
async function run() {
await init();
}
run();
</script>