# 20. WebAssembly

> Chapter 20: run Alice in the browser with kind = "wasm", call it from JavaScript and JavaScript from it, build a static site, and know what is planned for a runtime-free target.

Canonical: https://alice-lang.org/documentation/learn/webassembly/

[Documentation index](https://alice-lang.org/documentation/llms.txt) · [Complete book](https://alice-lang.org/llms-full.txt)

WebAssembly, or wasm, is a compact bytecode that every modern browser runs, close to native speed and inside the browser's sandbox. With it, the same Alice code can run on a server and in a web page: a price calculator, a game, a document viewer.

## 20.1 A wasm package

Create a package of kind `wasm`:

```sh
alice new web --wasm
cd web
alice run
```

```text
web is running in WebAssembly
```

The template contains:

```text
web/
  alice.toml          # kind = "wasm"
  src/main.al         # the program
  wwwroot/index.html  # the page
  wwwroot/main.js     # starts .NET in the page and calls Alice
```

`alice run` builds the package and runs it under Node.js, with the same .NET WebAssembly runtime the browser uses. The first run downloads that runtime from NuGet and takes a little while; later runs are quicker.

## 20.2 Talking to JavaScript

Mark a method `@[JSExport]` to make it callable from JavaScript. The template's `src/main.al`:

```alice skip="a wasm package: built by alice build, which needs the WebAssembly runtime packages"
using System.Runtime.InteropServices.JavaScript

module App
  @[JSExport]
  def self.greet(who : String) : String
    "Hello, #{who}!"
  end
end

puts "web is running in WebAssembly"
```

And the JavaScript side calls it:

```js
const { getAssemblyExports, getConfig, runMain } = await dotnet.create();
const app = await getAssemblyExports(getConfig().mainAssemblyName);
console.log(app.App.greet('browser'));
await runMain();   // runs the program's top-level code
```

In the other direction, a body-less `partial def` with `@[JSImport("globalThis.console.log")]` declares a JavaScript function that Alice code can call.

## 20.3 Building a site

```sh
alice build --release
```

writes the whole static site to `dist/wwwroot`, ready for any static host. A release build is trimmed: a hello world is about 2 MB over the wire with Brotli compression. It also enables wasm SIMD, so the vectorized loops of chapter 12 still use vector instructions. With the `wasm-tools` workload installed (`dotnet workload install wasm-tools`), it compiles ahead of time to WebAssembly for more speed.

## 20.4 What is different in the browser

- **One thread.** The browser runs .NET on a single thread, so parallel loops, forks and pipelines compile to their serial form. The safety checks still apply: a `par for` that is not provably independent is still an error, so the same code stays correct on a server.
- **No files, processes or native libraries.** `lib` functions and `@[Native]` are not available.
- **Invariant globalization by default** in release builds. Set `[runtime] globalization = "culture"` if you need culture-specific sorting and formatting, at the cost of downloading ICU data.

## 20.5 Coming: wasm without the .NET runtime

Today's wasm packages carry the .NET runtime, which is why the download is measured in megabytes and startup in hundreds of milliseconds. For pure Alice code, that runtime is not needed. The plan for 1.0 is a second wasm backend, selected with `[build] runtime = "alice"`, that compiles Alice directly to a small wasm module with a thin runtime of its own. It is designed but not available yet; [Appendix E](https://alice-lang.org/documentation/learn/coming-in-1-0.md) has the details. Until then, `kind = "wasm"` is the way to run Alice in a browser.

:::caution\[Common mistakes]

- **Expecting parallel speedups in the browser.** Wasm packages are single-threaded.
- **Using files or native libraries.** The browser sandbox has neither.
- **Serving the `wwwroot` of the source tree.** Deploy `dist/wwwroot` from `alice build --release`.
- **Assuming `runtime = "alice"` works.** It is planned for 1.0, not available in 0.14.
  :::

## Exercises

1. Add an exported method `App.add(a : Int32, b : Int32) : Int32` and call it from `main.js`.
2. Why can the same `par for` loop be used in a server package and a wasm package?

<details>
<summary>Answers</summary>

1. Add the method to the module:

   ```alice skip="a wasm package"
   module App
     @[JSExport]
     def self.add(a : Int32, b : Int32) : Int32
       a + b
     end
   end
   ```

   and call it in `main.js` after `getAssemblyExports`: `console.log(app.App.add(2, 3));` prints `5`.

2. The compiler proves the loop's iterations independent in both cases. On the server they run on all cores; in the browser they run one after another. Either order gives the same result, because the iterations are independent.

</details>

## Summary

- `alice new NAME --wasm` creates a browser package; `alice run` runs it under Node; `alice build --release` writes a static site to `dist/wwwroot`.
- `@[JSExport]` exposes Alice methods to JavaScript; `@[JSImport]` partial methods call JavaScript.
- The browser is single-threaded and sandboxed: parallel forms run serially, and files and native code are unavailable.
- A runtime-free wasm target, `runtime = "alice"`, is planned for 1.0.

[Chapter 21](https://alice-lang.org/documentation/learn/tooling.md) collects the tools you use every day.

## Continue reading

- Previous: [19. Web, desktop and games](https://alice-lang.org/documentation/learn/applications.md)
- Next: [21. Tooling](https://alice-lang.org/documentation/learn/tooling.md)
