Неверный или неожиданный токен в WebAssembly
Я пытаюсь запустить программу WebAssembly (написанную на Rust, пример программы из https://rustwasm.github.io/book/game-of-life/hello-world.html) с Rocket. WebAssembly компилируется с помощью wasm-pack и использует wasm_bindgen. Двоичный файл wasm представлен в виде content::JavaScript<Vec<u8>>
в Rocket, и кажется, что это "рабочее" решение. Двоичный файл выбирается "правильно", однако Chrome печатает Uncaught SyntaxError: Invalid или неожиданный токен. Это из-за представления как content::JavaScript<Vec<u8>>
что во время выборки произошла ошибка (хотя байты отправки совпадают с байтами в файле wasm) или ошибка в другом месте?
Я надеюсь, что кто-то может объяснить мне, почему в сгенерированном двоичном файле есть ошибка SyntaxError.
1 ответ
Хорошо, теперь я думаю, что знаю, что пошло не так: файл js, сгенерированный из пакета wasm, пытается загрузить WebAssembly как модуль. Модуль должен иметь MIME Javascript, иначе он потерпит неудачу (поэтому я попытался отправить файл wasm как content::JavaScript<Vec<u8>>
), но, очевидно, загрузка wasm как модуля не поддерживается (поправьте меня, если я ошибаюсь), поэтому, конечно, он найдет недопустимый токен в двоичном файле, потому что он пытается интерпретировать его как простой javascript. Что я на самом деле использую сейчас Option<NamedFile>
типа от Ракетной ведьмы есть application/wasm
мим.
Мне нужно было немного изменить сгенерированный файл js: WebAssembly инициализируется с WebAssembly.instatiateStreaming(fetch(...), importObjects)
, импорт модуля должен быть удален. importObjects
тоже было немного сложно, потому что передача стрингов в 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. Последнее, что нужно изменить, - это объект, который был изначально импортирован через import
заявление. У меня теперь есть переменная, которая имеет содержимое из obj.instance.exports
который установлен в тогдашнем утверждении от WebAssembly.instatiateStreaming(fetch(...), importObjects).then(obj => {
wasm = obj.instance.exports;
})
С этими изменениями у меня получилось (отправка и чтение строк в / из WebAssembly)
Продолжая ответ Бена. В.wasm
файл отправляется с application/javascript
mime, таким образом, браузер пытается выполнить его как javascript. отправить его сapplication/wasm
mime убедитесь, что ваш ответ имеет тип 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()
}
Что касается второй проблемы - получается, а не вручную редактировать javascript, сгенерированный wasm-pack build
вы действительно можете спросить wasm-pack
чтобы сгенерировать javascript, который можно запустить в браузере и загрузить ваш wasm. просто делай
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>