Introduction to WebAssembly Text

Previous   Next
Creating a WebAssembly Module Up WAT Datatypes

3: Using a Language Runtime as a WebAssembly Host Environment

Now that we can call our slightly-less-useless WebAssembly module from the command line, let’s look at calling it from a JavaScript program. In other words, we’re now going to use JavaScript as the WebAssembly host environment.

Create a .wasm file

When using wasmer as the host environment, behind the scenes it performed two tasks. It:

  1. Compiled the .wat file into a .wasm file, then
  2. Executed the .wasm file

However, when a language runtime such as JavaScript acts as the host environment, these two tasks are typically performed at different times in the development process.

So first, we need to assemble the WebAssembly Text file into a .wasm file. To do this, change into the same directory as the .wat file, then invoke the wat2wasm tool:

wat2wasm 02-slightly-less-useless.wat

This now creates a .wasm file that is a mere 39 bytes in size.

Since there are some implementation differences between a server-side JavaScript environment and a browser-based JavaScript environment, it is necessary to provide two versions of the following example.

Using JavaScript (NodeJS) as the WebAssembly Host Environment

As a prerequisite for using NodeJS, we must first create a package.json file containing the single line:

{ "type": "module" }

Next, we need to create a JavaScript program that does the following:

  1. Synchronously read the contents of the .wasm file into a constant called wasmBin
  2. Create an executable instance of the .wasm file using WebAssembly.instantiate()
  3. Using the wasmObj’s instance property, we can call the answer function via the exports property.

03-nodejs-host-env.js

import { readFileSync } from 'fs'

const start = async () => {
  const wasmBin = readFileSync('./02-slightly-less-useless.wasm')
  const wasmObj = await WebAssembly.instantiate(wasmBin)

  console.log(`Answer = ${wasmObj.instance.exports.answer()}`)
}

start()

Open a command line and run the above program using NodeJS

node 03-wasm-host-env.js
Answer = 42

Using JavaScript (Browser) as the WebAssembly Host Environment

If we now want to run the same WebAssembly module in a browser, we must modify the ablove JvaScript code slightly and wrap it in HTML:

03-browser-host-env.html

<!DOCTYPE html>
<html>
<script>
  const start = async () => {
    const wasmObj = await WebAssembly.instantiateStreaming(fetch('./02-slightly-less-useless.wasm'))

    console.log(`Answer = ${wasmObj.instance.exports.answer()}`)
  }

  start()
</script>

</html>

Place this file under your local webserver’s document root directory and display it through the browser. In your browser’s developer tools, you will see Answer = 42 displayed in the console.


IMPORTANT TECHNICAL DETAILS

  1. For security reasons, browsers will not open .wasm files using the file:// protocol. This means therefore that the web page within which this JavaScript code executes cannot be opened simply by pointing your browser at the .html file in your local file system. Any Web page containing a WebAssembly module must be supplied to the browser using your local Web Server.

  2. Your local Web Server must be correctly configured to send .wasm files with the correct MIME type of application/wasm.

    For example on a macOS machine, ensure that the file /private/etc/apache2/mime.types contains the line:
    application/wasm     wasm

  3. If you are developing a WebAssembly program in which multiple instances of the same module will simultaneously act upon the same block of shared memory (by means of JavaScript Web Workers), then your local Web Server must additionally be configured to supply the .wasm file with the following HTTP headers:

    Cross-Origin-Embedder-Policy: require-corp
    Cross-Origin-Opener-Policy: same-origin
    

    If you are using Apache as your WebServer, then the <Ifmodule headers_module> section of httpd.conf should contain at least these directives:

    <IfModule headers_module>
        Header set Cross-Origin-Embedder-Policy "require-corp"
        Header set Cross-Origin-Opener-Policy "same-origin"
     </IfModule>
    

Let’s now take a more detailed look at how to write a useful WebAssembly Text program.