Skip to content

Commit 4143aeb

Browse files
authored
feat: build WASM from ghostty-org/ghostty submodule with patches (#23)
1 parent 4cdb614 commit 4143aeb

12 files changed

Lines changed: 1179 additions & 39 deletions

File tree

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
name: 'Setup Zig'
2+
description: 'Install Zig compiler'
3+
inputs:
4+
version:
5+
description: 'Zig version to install'
6+
required: true
7+
default: '0.15.2'
8+
runs:
9+
using: 'composite'
10+
steps:
11+
- name: Cache Zig
12+
uses: actions/cache@v4
13+
id: cache-zig
14+
with:
15+
path: |
16+
~/zig
17+
key: zig-${{ runner.os }}-${{ inputs.version }}
18+
19+
- name: Download and install Zig
20+
if: steps.cache-zig.outputs.cache-hit != 'true'
21+
shell: bash
22+
run: |
23+
set -e
24+
VERSION="${{ inputs.version }}"
25+
26+
# Determine platform
27+
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
28+
PLATFORM="linux"
29+
ARCH="x86_64"
30+
elif [[ "$OSTYPE" == "darwin"* ]]; then
31+
PLATFORM="macos"
32+
if [[ "$(uname -m)" == "arm64" ]]; then
33+
ARCH="aarch64"
34+
else
35+
ARCH="x86_64"
36+
fi
37+
else
38+
echo "Unsupported OS: $OSTYPE"
39+
exit 1
40+
fi
41+
42+
# Download from ziglang.org
43+
# Note: Format changed in 0.14.1+ from zig-linux-x86_64 to zig-x86_64-linux
44+
TARBALL="zig-${ARCH}-${PLATFORM}-${VERSION}.tar.xz"
45+
URL="https://ziglang.org/download/${VERSION}/${TARBALL}"
46+
47+
echo "Downloading Zig ${VERSION} for ${PLATFORM}-${ARCH}..."
48+
curl --retry 3 --retry-delay 5 -L -o "/tmp/${TARBALL}" "${URL}"
49+
50+
# Extract to home directory
51+
mkdir -p ~/zig
52+
tar -xf "/tmp/${TARBALL}" -C ~/zig --strip-components=1
53+
54+
echo "Zig ${VERSION} installed to ~/zig"
55+
56+
- name: Add Zig to PATH
57+
shell: bash
58+
run: |
59+
echo "$HOME/zig" >> $GITHUB_PATH
60+
61+
- name: Verify Zig installation
62+
shell: bash
63+
run: |
64+
zig version

.github/workflows/ci.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,20 @@ jobs:
6060
runs-on: ubuntu-latest
6161
steps:
6262
- uses: actions/checkout@v4
63+
with:
64+
submodules: recursive
6365

6466
- uses: oven-sh/setup-bun@v1
6567
with:
6668
bun-version: latest
6769

70+
- uses: ./.github/actions/setup-zig
71+
with:
72+
version: 0.15.2
73+
74+
- name: Build WASM
75+
run: ./scripts/build-wasm.sh
76+
6877
- name: Install dependencies
6978
run: bun install
7079

@@ -76,11 +85,29 @@ jobs:
7685
runs-on: ubuntu-latest
7786
steps:
7887
- uses: actions/checkout@v4
88+
with:
89+
submodules: recursive
7990

8091
- uses: oven-sh/setup-bun@v1
8192
with:
8293
bun-version: latest
8394

95+
- uses: ./.github/actions/setup-zig
96+
with:
97+
version: 0.15.2
98+
99+
- name: Build WASM
100+
run: ./scripts/build-wasm.sh
101+
102+
- name: Check WASM size
103+
run: |
104+
SIZE=$(stat -c%s ghostty-vt.wasm)
105+
echo "WASM size: $SIZE bytes"
106+
if [ "$SIZE" -gt 524288 ]; then
107+
echo "❌ Error: WASM exceeds 512 KB limit"
108+
exit 1
109+
fi
110+
84111
- name: Install dependencies
85112
run: bun install
86113

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@ dist/
33
.DS_Store
44
*.log
55
.vite/
6+
7+
# WASM build output (built locally and in CI)
8+
ghostty-vt.wasm

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "ghostty"]
2+
path = ghostty
3+
url = https://github.com/ghostty-org/ghostty.git

.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ coverage/
55
.git/
66
.vite/
77
bun.lock
8+
ghostty/

INSTALL.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ npm install github:coder/ghostty-web
2020
bun add github:coder/ghostty-web
2121
```
2222

23-
**Note:** When installing from git, the package automatically builds itself via a `postinstall` script. This requires Bun to be installed and may take a few seconds during installation.
23+
**Note:** Git installs require manually building the package first. See [Local Development](#local-development) for build instructions.
2424

2525
## Basic Usage
2626

@@ -91,7 +91,17 @@ ws.onmessage = (event) => {
9191

9292
## WASM File Handling
9393

94-
The library requires the `ghostty-vt.wasm` file at runtime. Most bundlers handle this automatically.
94+
The library requires the `ghostty-vt.wasm` file at runtime. When installing from npm, the WASM is pre-built and included in the package.
95+
96+
### Local Development
97+
98+
After cloning:
99+
100+
```bash
101+
./scripts/build-wasm.sh
102+
```
103+
104+
The script will automatically initialize the submodule if needed. The WASM file is generated locally and gitignored.
95105

96106
### Vite (Recommended)
97107

README.md

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ Or install from GitHub:
1414
npm install github:coder/ghostty-web
1515
```
1616

17-
**Note:** Git installs will auto-build during `postinstall` (requires Bun).
18-
1917
## Quick Start
2018

2119
```typescript
@@ -218,30 +216,48 @@ WebSocket Server (server/file-browser-server.ts)
218216
└── ghostty-vt.wasm - Ghostty VT100 parser (122 KB)
219217
```
220218

221-
## Building
219+
## Building WASM
220+
221+
The WASM binary is built from source, not committed to the repo.
222+
223+
**Requirements:**
222224

223-
Requires:
225+
- Zig 0.15.2+
226+
- Git submodules initialized
224227

225-
- **Zig 0.15.2+** (to build WASM)
226-
- **Ghostty source** (from GitHub)
228+
**Build:**
227229

228230
```bash
229-
# Install Zig 0.15.2
230-
curl -L -o zig-0.15.2.tar.xz \
231-
https://ziglang.org/download/0.15.2/zig-x86_64-linux-0.15.2.tar.xz
232-
tar xf zig-0.15.2.tar.xz
233-
sudo cp -r zig-x86_64-linux-0.15.2 /usr/local/zig-0.15.2
234-
sudo ln -sf /usr/local/zig-0.15.2/zig /usr/local/bin/zig
235-
236-
# Clone Ghostty
237-
git clone https://github.com/ghostty-org/ghostty.git
238-
cd ghostty
231+
# Initialize submodule (first time only)
232+
git submodule update --init --recursive
233+
234+
# Build WASM
235+
./scripts/build-wasm.sh
236+
# or
237+
bun run build:wasm
238+
```
239239

240-
# Build WASM (~20 seconds)
241-
zig build lib-vt -Dtarget=wasm32-freestanding -Doptimize=ReleaseSmall
242-
# Output: zig-out/bin/ghostty-vt.wasm (122 KB)
240+
**What it does:**
241+
242+
1. Initializes `ghostty/` submodule (ghostty-org/ghostty)
243+
2. Applies patches from `patches/ghostty-wasm-api.patch`
244+
3. Builds WASM with Zig (takes ~20 seconds)
245+
4. Outputs `ghostty-vt.wasm` (404 KB)
246+
5. Reverts patch to keep submodule clean
247+
248+
**Updating Ghostty:**
249+
250+
```bash
251+
cd ghostty
252+
git fetch origin
253+
git checkout <commit-or-tag>
254+
cd ..
255+
./scripts/build-wasm.sh
256+
# Test, then commit the updated submodule pointer
243257
```
244258

259+
**CI:** The WASM is built as part of the `test` and `build` jobs.
260+
245261
## Testing
246262

247263
Run the test suite:

ghostty

Submodule ghostty added at 0f64b9a

ghostty-vt.wasm

-403 KB
Binary file not shown.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@
4646
},
4747
"scripts": {
4848
"dev": "vite --port 8000",
49-
"build": "bun run clean && bun run build:lib && bun run build:wasm-copy",
49+
"build": "bun run clean && bun run build:wasm && bun run build:lib && bun run build:wasm-copy",
50+
"build:wasm": "./scripts/build-wasm.sh",
5051
"build:lib": "vite build",
5152
"build:wasm-copy": "cp ghostty-vt.wasm dist/",
5253
"clean": "rm -rf dist",
@@ -57,8 +58,7 @@
5758
"fmt:fix": "prettier --write .",
5859
"lint": "biome check .",
5960
"lint:fix": "biome check --write .",
60-
"prepublishOnly": "bun run test && bun run build",
61-
"postinstall": "[ -d dist ] || bun run build"
61+
"prepublishOnly": "bun run test && bun run build"
6262
},
6363
"devDependencies": {
6464
"@biomejs/biome": "^1.9.4",

0 commit comments

Comments
 (0)