I'm using MongoDB Realm / App Services to make a web front end for an existing iOS app.
The standard Realm Web SDK only permits authentication and backend functions, so I am trying to use the preview release of the Web Assembly version ([email protected]
) so that I can use device sync and interact with a Realm object in the way I'm used to.
Details at: Get Started with Realm Web & Atlas Device Sync (Preview)
I am just using the basic app scaffold created by Vite, and then importing Realm in App.vue
. I am not (yet) using Realm anywhere else in the code.
import Realm, { App } from "realm";
As advised in the Realm SDK documentation, for the Web Assembly version I had to enable top-level await in vite.config.js
:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
esbuild: {
supported: {
'top-level-await': true
},
},
optimizeDeps: {
esbuildOptions: {
supported: {
"top-level-await": true
},
},
},
})
So this works without errors when I build and preview (vite build
followed by vite preview
).
However, when I do npm run dev
(vite
), the server starts as expected, but there are the following errors in the browser console:
[Error] wasm streaming compile failed: TypeError: Unexpected response MIME type. Expected 'application/wasm'
(anonymous function) (realm.js:726)
[Error] falling back to ArrayBuffer instantiation
(anonymous function) (realm.js:727)
[Error] failed to asynchronously prepare wasm: CompileError: WebAssembly.Module doesn't parse at byte 0: module doesn't start with '\0asm'
(anonymous function) (realm.js:717)
[Error] Aborted(CompileError: WebAssembly.Module doesn't parse at byte 0: module doesn't start with '\0asm')
abort (realm.js:661)
(anonymous function) (realm.js:718)
This doesn't happen if I build and preview, so I hope it won't actually be a problem, but I don't understand what is going on here and I'm curious about how to fix it for working during the development process.
Thanks to VonC for the answer (now deleted?). I tried using the custom middleware, but got errors that the file cannot be found.
The .wasm
files are in node_modules/realm/dist
, but it seems to be looking in node_modules/.vite
instead.
This is the error if I use const wasmPath = path.join(__dirname, req.url);
(i.e. without the public
path component).
ENOENT: no such file or directory, open '<my_local_path>/vite-project/node_modules/.vite/deps/realm-js-wasm.wasm'
In the end I got it working by using the middleware solution and redirecting it to the Realm folder directly:
const wasmPath = path.join(__dirname, 'node_modules/realm/dist', path.basename(req.url));
I got this working by adapting the answer by @VonC. I had to use custom middleware to redirect to the correct location of .wasm
files.
The .wasm
files are in node_modules/realm/dist
. I got it working by using the middleware solution and redirecting it to the Realm folder directly:
const wasmPath = path.join(__dirname, 'node_modules/realm/dist', path.basename(req.url));
My final vite.config
file:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import fs from 'fs'
import path from 'path'
// Custom middleware to serve wasm files with the correct MIME type
const wasmMiddleware = () => {
return {
name: 'wasm-middleware',
configureServer(server) {
server.middlewares.use((req, res, next) => {
if (req.url.endsWith('.wasm')) {
const wasmPath = path.join(__dirname, 'node_modules/realm/dist', path.basename(req.url));
const wasmFile = fs.readFileSync(wasmPath);
res.setHeader('Content-Type', 'application/wasm');
res.end(wasmFile);
return;
}
next();
});
},
};
};
export default defineConfig({
plugins: [vue(), wasmMiddleware()],
esbuild: {
supported: {
'top-level-await': true
},
},
optimizeDeps: {
esbuildOptions: {
supported: {
"top-level-await": true
},
},
},
})