webassemblywebidl

Can WASM access the DOM without any JavaScript?


Is there any way to get read/write access to DOM and/or the WebAPIs(i.e. fullscreen API) without JavaScript?

I'm trying to build a basic application in C(C source being actually the result of transpilation from a GC language). The app I'm building will run as Desktop app(it's not meant to run in "real" browsers yet) so I can tweak the environment(i.e. the layout engine) if necessary.


Solution

  • It all depends on compiler capabilities.

    Currently there is no way to access the DOM or any other browser API directly. It is also not possible to store JavaScript references inside of Wasm linear memory or Wasm tables. It is also not possible to use JavaScript references as function arguments or return values. They just do not exists in the MVP type system. However, there is the Reference Type Proposal, which might someday become part of the Wasm runtime, but there is no official release date available.

    So, how can Wasm to Host Environment interaction be done? Well, it turns out that the Wasm module system with imports and exports can be used to create an emulation layer. Creating this layer by hand is painful, so it is a good task for a compiler to create it. But how?

    For instance, we want to set the document title in the current browser window. The Wasm needs to access the current window instance, select the document, and set the title property of it. As the Wasm runtime cannot access the references, we need to create a mapping table on JS side and some JS functions with mapping logic and import them into the Wasm module.

    So, we create a function called getWindow. This function takes the global window reference, puts it into a mapping table and returns the index in the table. This index will be accessible as an I32 on Wasm side. This function is imported into the Wasm module.

    Now, we create a function called getDocumentFromWindow. This function takes an index into the mapping table, and returns another index. The implementation looks up the window reference from the mapping table and resolves its document property, and puts this document into the mapping table and returns that index to Wasm. This function is also imported into the Wasm module.

    On the Wasm side, we can now indirectly manipulate Wasm host references by our imported functions. Our mapping table emulates JS references by integer indices. This is a slower version of what might come with the Wasm Reference Type proposal.

    So this whole mapping logic can be created by the compiler. Once reference types are available, the compiler can be changed and use the new type system for more efficient code.

    It you want to see such kind if compiler in action, take a look at https://github.com/mirkosertic/Bytecoder. It can compile JVM bytecode to JavaScript and WebAssembly and provides a transparent way for DOM and Browser API interaction in both ways. It is possible to call DOM from Wasm, and it is also possible to call Wasm from DOM, for instance to implement click-listeners and other cool stuff like interaction with high level frameworks like vue.js.

    Disclaimer: I am the inventor of Bytecoder, but the described logic can be adapted to any other compiler.