Skip to content

Commit a28278b

Browse files
committed
feat: switch to component model for wit-bindgen-wasm
Time to eat our own dog food Signed-off-by: Gordon Smith <GordonJSmith@gmail.com>
1 parent c9c8d4d commit a28278b

File tree

12 files changed

+615
-1157
lines changed

12 files changed

+615
-1157
lines changed

package-lock.json

Lines changed: 1 addition & 217 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@
3939
"test-navigator-polyfill": "vitest run tests/navigator-polyfill.test.ts",
4040
"gen-types": "tsc --project tsconfig.json --emitDeclarationOnly",
4141
"gen-watch": "npm run gen-types -- -w",
42-
"build-wasm-prod": "cd wit-bindgen-wasm && wasm-pack build --target web --out-dir pkg --release",
43-
"build-wasm": "cd wit-bindgen-wasm && wasm-pack build --target web --out-dir pkg",
42+
"build-wasm-prod": "./scripts/build-wasm.sh --release",
43+
"build-wasm": "./scripts/build-wasm.sh --release",
4444
"build-extension-prod": "node esbuild.mts -- --production",
4545
"build-extension": "node esbuild.mts",
4646
"build-extension-watch": "node esbuild.mts --watch",
@@ -56,7 +56,7 @@
5656
"test": "run-s lint fmt-check build package gen-types test-grammar test-unit",
5757
"test-wasm": "cd wit-bindgen-wasm && cargo test",
5858
"check-wasm": "cd wit-bindgen-wasm && cargo check",
59-
"verify-wasm": "node -e \"console.log('Verifying WASM build...'); const fs = require('fs'); const path = 'wit-bindgen-wasm/pkg/wit_bindgen_wasm_bg.wasm'; if (fs.existsSync(path)) { console.log('✅ WASM file exists:', path); const size = Math.round(fs.statSync(path).size / 1024); console.log('📏 Size:', size, 'KB'); try { const fd = fs.openSync(path, 'r'); const header = Buffer.alloc(8); fs.readSync(fd, header, 0, 8, 0); fs.closeSync(fd); const magicOk = header[0] === 0x00 && header[1] === 0x61 && header[2] === 0x73 && header[3] === 0x6D; if (!magicOk) { console.warn('⚠️ Not a WebAssembly binary (bad magic).'); process.exit(1); } const version = header.readUInt32LE(4); if (version === 1) { console.log('🧩 Type: Core WebAssembly module (vanilla wasm)'); } else if (version === 0x0A) { console.log('🧩 Type: WebAssembly component'); } else { console.log('🧩 Type: Unknown/other (version ' + version + ')'); } } catch (e) { console.error('❌ Error reading header:', e.message); process.exit(1); } } else { console.error('❌ WASM file not found:', path); process.exit(1); }\"",
59+
"verify-wasm": "node -e \"console.log('Verifying WASM build...'); const fs = require('fs'); const path = 'wit-bindgen-wasm/pkg/wit_bindgen_wasm.core.wasm'; if (fs.existsSync(path)) { console.log('✅ WASM file exists:', path); const size = Math.round(fs.statSync(path).size / 1024); console.log('📏 Size:', size, 'KB'); try { const fd = fs.openSync(path, 'r'); const header = Buffer.alloc(8); fs.readSync(fd, header, 0, 8, 0); fs.closeSync(fd); const magicOk = header[0] === 0x00 && header[1] === 0x61 && header[2] === 0x73 && header[3] === 0x6D; if (!magicOk) { console.warn('⚠️ Not a WebAssembly binary (bad magic).'); process.exit(1); } const version = header.readUInt32LE(4); if (version === 1) { console.log('🧩 Type: Core WebAssembly module'); } else if (version === 0x0A) { console.log('🧩 Type: WebAssembly component'); } else { console.log('🧩 Type: Unknown/other (version ' + version + ')'); } console.log('✅ WASM verification passed'); } catch (e) { console.error('❌ Error reading header:', e.message); process.exit(1); } } else { console.error('❌ WASM file not found:', path); process.exit(1); }\"",
6060
"dev": "run-p gen-watch build-extension-watch",
6161
"publish": "npx -y @vscode/vsce publish",
6262
"publish-ovsx": "ovsx publish",
@@ -93,8 +93,7 @@
9393
"typescript": "5.9.3",
9494
"typescript-eslint": "8.57.1",
9595
"vitest": "4.1.0",
96-
"vscode-tmgrammar-test": "0.1.3",
97-
"wasm-pack": "0.14.0"
96+
"vscode-tmgrammar-test": "0.1.3"
9897
},
9998
"contributes": {
10099
"colors": [

scripts/build-wasm.sh

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#!/bin/bash
2+
3+
# Build WebAssembly component from Rust source
4+
# Uses: cargo (Rust), wasm-tools (component model), jco (JS transpilation)
5+
6+
set -e
7+
8+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9+
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
10+
WASM_DIR="$PROJECT_DIR/wit-bindgen-wasm"
11+
PKG_DIR="$WASM_DIR/pkg"
12+
TARGET_DIR="$WASM_DIR/target"
13+
14+
# Parse arguments
15+
RELEASE_FLAG=""
16+
CARGO_PROFILE="debug"
17+
if [[ "$1" == "--release" ]]; then
18+
RELEASE_FLAG="--release"
19+
CARGO_PROFILE="release"
20+
fi
21+
22+
echo "🔨 Building WebAssembly component..."
23+
24+
# Step 1: Build the Rust code to a core WASM module
25+
echo "📦 Step 1/4: Compiling Rust to WebAssembly..."
26+
cd "$WASM_DIR"
27+
cargo build --target wasm32-unknown-unknown $RELEASE_FLAG
28+
29+
CORE_WASM="$TARGET_DIR/wasm32-unknown-unknown/$CARGO_PROFILE/wit_bindgen_wasm.wasm"
30+
if [ ! -f "$CORE_WASM" ]; then
31+
echo "❌ Core WASM not found at: $CORE_WASM"
32+
exit 1
33+
fi
34+
echo " Core module: $(du -h "$CORE_WASM" | cut -f1)"
35+
36+
# Step 2: Embed WIT metadata into the core module
37+
echo "🔗 Step 2/4: Embedding WIT component type information..."
38+
EMBEDDED_WASM="$TARGET_DIR/wit_bindgen_wasm.embedded.wasm"
39+
wasm-tools component embed wit/ "$CORE_WASM" --world wit-bindgen-wasm -o "$EMBEDDED_WASM"
40+
41+
# Step 3: Create the WebAssembly component
42+
echo "🧩 Step 3/4: Creating WebAssembly component..."
43+
COMPONENT_WASM="$TARGET_DIR/wit_bindgen_wasm.component.wasm"
44+
wasm-tools component new "$EMBEDDED_WASM" -o "$COMPONENT_WASM"
45+
echo " Component: $(du -h "$COMPONENT_WASM" | cut -f1)"
46+
47+
# Step 4: Transpile to JavaScript using jco
48+
echo "🔄 Step 4/4: Transpiling component to JavaScript..."
49+
mkdir -p "$PKG_DIR/interfaces"
50+
51+
# Clean old generated files (preserve package.json)
52+
find "$PKG_DIR" -name "*.js" -o -name "*.d.ts" -o -name "*.wasm" | xargs rm -f 2>/dev/null || true
53+
rm -rf "$PKG_DIR/interfaces/"
54+
55+
npx jco transpile "$COMPONENT_WASM" -o "$PKG_DIR" --name wit_bindgen_wasm
56+
57+
# Ensure package.json exists for npm resolution
58+
cat > "$PKG_DIR/package.json" << 'PKGJSON'
59+
{
60+
"name": "wit-bindgen-wasm",
61+
"type": "module",
62+
"description": "WebAssembly component wrapper for wit-bindgen",
63+
"version": "0.1.0",
64+
"license": "Apache-2.0 WITH LLVM-exception",
65+
"files": [
66+
"wit_bindgen_wasm.core.wasm",
67+
"wit_bindgen_wasm.js",
68+
"wit_bindgen_wasm.d.ts",
69+
"interfaces/"
70+
],
71+
"main": "wit_bindgen_wasm.js",
72+
"types": "wit_bindgen_wasm.d.ts"
73+
}
74+
PKGJSON
75+
76+
echo ""
77+
echo "✅ WebAssembly component build complete!"
78+
echo " Output: $PKG_DIR/"
79+
ls -la "$PKG_DIR/"

0 commit comments

Comments
 (0)