A packer that adds a webpage to WASM module, making it self-hosted!
Motivation
At the moment, Browsers can not execute WebAssembly as a native single page app. Hopefully, this will change at some point. This 'packer' allows you to preserve the WebAssembly interpretation, unchanged, while adding an HTML loader as a form of polyfill for the native loader environment.
That said you could also regard it as a more general tool for WebAssembly plugins, as a form of hypervisor. Provide a stage2 loader that emulates the host environment within an HTML page. This could be, for instance, a WASI environment with a file system in local storage. Such an app can be ran natively or deployed to a browser as a 'hardware-agnostic' alternative, from a single binary file.
How to use it
The 'packer' acts as a filter for a WebAssembly module. It's a standard clap app if you want to explore its command line options.
# Assume you want to deploy a 'TodoMVC' app:
wasm-as-html --index-html /my/index.html /my/todomvc.js < /my/todomvc_bg.wasm > todomvc.html
See [examples/yew/Readme.md] for a specific description.
Or TodoMVC deployed on gh-pages.
Experimental
There's an experimental --edit
flag. This replaces stage1 with an auto-reload driver, which will periodically refetch the document to compare hashes. It will the invoke the entrypoint with the new bytes, again.
How it works
The packer takes two arguments: A webassembly module, and a stage 2 loader javascript file that will be given control over the page and passed the a (fake) Promise to a Response that resolves to the web assembly bytes. The recommended stage 2 is some web-sys implementation that then passes control directly to a webassembly module. Its init
and default export take this exact argument to instantiate the bindings marked as its main function.
The technical inner workings:
-
The first section in WASM is a custom one that parses as HTML. The trick take from here implemented in an program fashion. Note that this
stage0
is not of arbitrary size. Otherwise the WebAssembly length encoding of the section's length will cause problems as they parse as good characters. This reads the first custom section of namepolyglot_stage1
. -
The second section is another custom one, which is our stage1 with arbitrary contents. We almost immediately dispatch here from stage0 leaving behind all notions of HTML that we started with. We're now preparing the web page for the module packed as stage2. That is, loading a new skeleton with expected elements that the module might need to bootstrap itself.
It reads the section title polyglot_stage1_html for contents of a new page, as well as the first
polyglot_stage2
for the subsequent module.
WIP: additionally, an auxiliary .zip
file can be passed. The packer then ensures that the result is also a valid zip archive with all files intact and such that they are accessible from the webassembly module as a custom module.