4

I'm trying to load a wasm module with a VSCode web extension.

I started from the "lsp-web-extension-sample". Within the server directory, I created a simple rust lib with wasm-bindgen, it successfully compiles with wasm-pack. When I call the init function from the rust pkg output, it basically does this:

input = new URL("my-ext.wasm", import.meta.url)
fetch(input)

I get the following error: "TypeError: failed to fetch", without more explanations. This error happens when testing with @vscode/test-web as well as when testing with the vsce package version.

Any idea what to do? Is there any example out there of a wasm web extension for vscode?

Cohars
  • 3,822
  • 1
  • 29
  • 50

3 Answers3

3

I was able to get the work done by loading wasm inline.

webpack.config.js

  module: {
    rules: [
      // ...,
      {
        test: /\.wasm$/,
        type: "asset/inline",
      },
    ],
  },
Cohars
  • 3,822
  • 1
  • 29
  • 50
1

Accepted solution didn't work for me (WASM generated by wasm-pack), but this did:

https://github.com/SonOfLilit/vscode-web-wasm-rust

It involved writing a webpack WASM Loader plugin (and patching webpack to make that possible, PR submitted) to use this loader:

/******/    /* webpack/runtime/wasm loading */
/******/    (() => {
/******/        __webpack_require__.v = (exports, wasmModuleId, wasmModuleHash, importsObj) => {
/******/            var vscode = require('vscode');
/******/            var wasmPath = __webpack_require__.p + wasmModuleHash + '.module.wasm';
/******/            var req = vscode.workspace.fs.readFile(vscode.Uri.file(wasmPath));;
/******/            return req
/******/                .then((bytes) => (WebAssembly.instantiate(bytes, importsObj)))
/******/                .then((res) => (Object.assign(exports, res.instance.exports)));
/******/        };
/******/    })();

as well as setting __webpack_public_path__ in activate before trying to import the WASM:

export function activate(context: vscode.ExtensionContext) {
  __webpack_public_path__ =
    context.extensionUri.toString().replace("file:///", "") + "/dist/web/";

  let disposable = vscode.commands.registerCommand(
    "vscode-rust-web.helloWorld",
    () => {
      require("rust-wasm").then((rust: any) => {
        vscode.window.showInformationMessage(rust.greet());
      });
    }
  );

  context.subscriptions.push(disposable);
}
Aur Saraf
  • 3,214
  • 1
  • 26
  • 15
0

It took me quite a while to figure this out too (as you can see in my comments below). This is the code I ended up with in my activate method.

export function activate(context: vscode.ExtensionContext) {

    // These few lines took a looooooong while to figure out.
    // fetch is patched by VS Code, but WebAssembly.instantiateStreaming isn't, so call fetch
    // directly and pass the Response to the wasm-pack init function.
    //
    // Some of this approach copied from:
    //   https://github.com/microsoft/vscode-anycode/blob/anycode.v0.0.70/anycode/client/src/common/client.ts#L114

    let wasmUri = vscode.Uri.joinPath(context.extensionUri, "./dist/bqm_wasm_bg.wasm");
    // Will be something like "file:///Users/billti/src/bqm/dist/hello_wasm_bg.wasm" running in VSCode.
    // Something like "http://localhost:3000/static/devextensions/dist/hello_wasm_bg.wasm" with npx @vscode/test-web

    let fixedUri = 'importScripts' in globalThis ? wasmUri.toString() : wasmUri.fsPath;
    let ready = fetch(fixedUri).then(
        response => init(response)
    );
Bill Ticehurst
  • 1,728
  • 12
  • 14