# How to Compile a TypePHP Project for the Browser Using WebAssembly (WASM)

> Compile your TypePHP project for the browser with WebAssembly WASM using our easy three-stage build process. Get started now!

- Repository: [Swoole Project/typephp](https://github.com/swoole/typephp)
- Tags: how-to-guide
- Published: 2026-08-30

---

**TypePHP provides native WASM compilation through a three-stage build process involving the SDK builder ([`wasm/build-sdk.sh`](https://github.com/swoole/typephp/blob/main/wasm/build-sdk.sh)), the program compiler ([`wasm/build-program.sh`](https://github.com/swoole/typephp/blob/main/wasm/build-program.sh)), and a browser loader ([`typephp.js`](https://github.com/swoole/typephp/blob/main/typephp.js)).**

TypePHP is a compiled PHP implementation maintained in the `swoole/typephp` repository that targets WebAssembly, enabling PHP applications to run client-side in modern browsers without a server-side runtime. This guide walks through the complete workflow to transform TypePHP source code into standalone WASM modules using the official build toolchain.

## Prerequisites for WASM Compilation

Before compiling, install **Clang/LLVM** with support for the `wasm32-unknown-wasi` target and **Node.js** (version 14 or higher) for JavaScript glue generation. The build scripts located in `wasm/` automatically detect these toolchains, but you can override paths via environment variables such as `LLVM_DIR` and `NODE_BIN`. Additionally, ensure **Emscripten** is available, as the SDK build process relies on `emconfigure` and `emmake` to compile the C++ sources.

## The Three-Stage Build Process

TypePHP compiles to WebAssembly through three distinct stages: building the SDK static library, compiling your specific PHP program, and deploying the resulting module to the browser.

### Stage 1 – Build the WASM SDK

Execute [`wasm/build-sdk.sh`](https://github.com/swoole/typephp/blob/main/wasm/build-sdk.sh) to compile the underlying C/C++ runtime engine into a WASM-compatible static library. This script processes the source files under `src/` using Emscripten, producing two key artifacts:

- `libtypephp.a`: The static library containing the compiled TypePHP engine
- [`typephp.js`](https://github.com/swoole/typephp/blob/main/typephp.js): A generic JavaScript loader that handles WebAssembly module instantiation, memory allocation, and string conversion between JavaScript and the WASM runtime

Run this stage once per environment setup:

```bash
cd wasm
./build-sdk.sh

```

### Stage 2 – Compile Your PHP Program

With the SDK built, use [`wasm/build-program.sh`](https://github.com/swoole/typephp/blob/main/wasm/build-program.sh) to translate your PHP source files into an executable WebAssembly module. This script wraps the `phpc` compiler (TypePHP's compiler) and invokes it with the `--wasm` flag to perform static analysis, build an intermediate representation, and emit the final binary.

Execute the compiler pointing to your source directory:

```bash
./build-program.sh myapp/ output.wasm

```

This command generates `output.wasm` (the compiled module) and [`output.js`](https://github.com/swoole/typephp/blob/main/output.js) (a project-specific loader pre-wired to your particular module). The generated loader re-exports the same API as the generic [`typephp.js`](https://github.com/swoole/typephp/blob/main/typephp.js) but is already configured to load your specific WASM file.

### Stage 3 – Load and Run in the Browser

Host the generated `output.wasm` and [`output.js`](https://github.com/swoole/typephp/blob/main/output.js) files on any static web server. Include the loader in an HTML page using ES modules:

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>TypePHP WASM Demo</title>
</head>
<body>
  <script type="module">
    import init from './output.js';
    // init returns a promise that resolves when the WASM instance is ready
    init().then(({ php }) => {
      // php is the entry point exported by the compiled module
      php(); // Executes your PHP script client-side
    });
  </script>
</body>
</html>

```

Opening this page in a modern browser downloads the `.wasm` file, instantiates it via the WebAssembly API, and executes your PHP code entirely client-side.

## Enabling WASI for File System Operations

To use PHP file functions such as `file_get_contents()` or `file_put_contents()`, compile with the `--wasi` flag to enable WASI (WebAssembly System Interface) support:

```bash
./build-program.sh . file_demo.wasm --wasi

```

The WASI implementation provides a sandboxed virtual filesystem. Pre-populate files at initialization by passing a `preloadFiles` configuration to the loader:

```html
<script type="module">
  import init from './file_demo.js';
  init({
    preloadFiles: [{ name: '/data.txt', content: 'Initial file contents' }]
  }).then(({ php }) => php());
</script>

```

This maps PHP's POSIX-like file calls onto the WASI system interface, allowing scripts to read from and write to an in-memory virtual filesystem. See [`docs/zh-cn/WASI_BUILD.md`](https://github.com/swoole/typephp/blob/main/docs/zh-cn/WASI_BUILD.md) for detailed WASI configuration options.

## Complete Working Examples

### Hello World Compilation

Create a simple PHP script named [`hello.php`](https://github.com/swoole/typephp/blob/main/hello.php):

```php
<?php
echo "Hello, WebAssembly!\n";
?>

```

Build the project using the two-stage process:

```bash
cd wasm
./build-sdk.sh                      # Build SDK once

./build-program.sh . hello.wasm    # Compile hello.php

```

Serve `hello.wasm` and [`hello.js`](https://github.com/swoole/typephp/blob/main/hello.js) alongside this HTML:

```html
<!DOCTYPE html>
<html>
<body>
  <script type="module">
    import init from './hello.js';
    init().then(({ php }) => php());
  </script>
</body>
</html>

```

Opening the page prints **"Hello, WebAssembly!"** to the browser console.

### Virtual File System Demo

For applications requiring file I/O, create [`file_demo.php`](https://github.com/swoole/typephp/blob/main/file_demo.php):

```php
<?php
file_put_contents('data.txt', 'WASM FS demo');
echo file_get_contents('data.txt');
?>

```

Compile with WASI support and preload a virtual file:

```bash
./build-program.sh . file_demo.wasm --wasi

```

Then initialize with filesystem preloading:

```html
<script type="module">
  import init from './file_demo.js';
  init({
    preloadFiles: [{ name: '/data.txt', content: '' }]
  }).then(({ php }) => php());
</script>

```

The script writes to and reads from the virtual [`/data.txt`](https://github.com/swoole/typephp/blob/main//data.txt) file, demonstrating how PHP's native filesystem functions map onto the WASI runtime provided by the TypePHP engine.

## Summary

- Run [`wasm/build-sdk.sh`](https://github.com/swoole/typephp/blob/main/wasm/build-sdk.sh) once to generate `libtypephp.a` and the generic [`typephp.js`](https://github.com/swoole/typephp/blob/main/typephp.js) loader from the C++ sources in `src/`
- Use `wasm/build-program.sh <source_dir> <output_name>` to compile PHP projects to WASM via the `phpc --wasm` compiler
- Deploy the generated `.wasm` binary and accompanying `.js` loader to any static web server
- Enable `--wasi` flag when using PHP file functions, and pre-populate the virtual filesystem via `preloadFiles` configuration
- Refer to [`wasm/README.md`](https://github.com/swoole/typephp/blob/main/wasm/README.md) for build troubleshooting and [`docs/zh-cn/PHPX_WASM_BUILD.md`](https://github.com/swoole/typephp/blob/main/docs/zh-cn/PHPX_WASM_BUILD.md) for detailed deployment guides

## Frequently Asked Questions

### What is the difference between [`build-sdk.sh`](https://github.com/swoole/typephp/blob/main/build-sdk.sh) and [`build-program.sh`](https://github.com/swoole/typephp/blob/main/build-program.sh)?

[`build-sdk.sh`](https://github.com/swoole/typephp/blob/main/build-sdk.sh) compiles the TypePHP C++ engine (located under `src/`) into the static library `libtypephp.a` and generates the generic JavaScript runtime glue [`typephp.js`](https://github.com/swoole/typephp/blob/main/typephp.js). [`build-program.sh`](https://github.com/swoole/typephp/blob/main/build-program.sh) invokes the `phpc` compiler to translate your specific PHP source files into a WebAssembly module and produces a project-specific loader script that references your compiled `.wasm` binary.

### Can I use standard PHP file functions in the browser?

Yes, when you compile with the `--wasi` flag enabled. The WASI implementation maps standard PHP file operations (such as `fopen`, `fread`, and `file_put_contents`) to an in-memory virtual filesystem. You can pre-populate files and directories at runtime using the `preloadFiles` option in the loader initialization object, as documented in [`docs/zh-cn/WASI_BUILD.md`](https://github.com/swoole/typephp/blob/main/docs/zh-cn/WASI_BUILD.md).

### How do I customize the toolchain paths for LLVM or Node.js?

Set the `LLVM_DIR` and `NODE_BIN` environment variables before executing the build scripts. The SDK builder automatically detects standard installation paths, but respects these overrides when provided, allowing you to use specific versions of Clang/LLVM or Node.js for the `wasm32-unknown-wasi` target compilation.

### Why is Emscripten required for the build process?

The TypePHP engine relies on Emscripten's `emconfigure` and `emmake` tools to compile the C++ source code into WebAssembly-compatible static libraries. Emscripten also generates the critical JavaScript glue code ([`typephp.js`](https://github.com/swoole/typephp/blob/main/typephp.js)) that bridges WebAssembly memory management, string marshalling, and exception handling between the browser's JavaScript environment and the compiled PHP runtime.