Skip to content

Commit 422644c

Browse files
committed
Add cross-platform support for WASM build scripts
- Add Windows Rust installation using rustup-init.exe - Add platform-specific binaryen installation (brew/apt-get/choco) - Improve error messages for missing prerequisites - Ensure builds work on ubuntu-latest, macos-latest, windows-latest
1 parent bf6801d commit 422644c

File tree

2 files changed

+141
-91
lines changed

2 files changed

+141
-91
lines changed

scripts/wasm/build-unified-wasm.mjs

Lines changed: 67 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -48,38 +48,6 @@ async function exec(command, args, options = {}) {
4848
}
4949
}
5050

51-
/**
52-
* Check if Homebrew is installed.
53-
*/
54-
async function checkBrewInstalled() {
55-
try {
56-
await exec('brew', ['--version'])
57-
return true
58-
} catch {
59-
return false
60-
}
61-
}
62-
63-
/**
64-
* Install Homebrew.
65-
*/
66-
async function installBrew() {
67-
console.log('📦 Installing Homebrew...')
68-
console.log(' This may take a few minutes...\\n')
69-
70-
try {
71-
const installScript =
72-
'/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"'
73-
await exec('bash', ['-c', installScript], { stdio: 'inherit' })
74-
console.log(' ✓ Homebrew installed successfully\\n')
75-
return true
76-
} catch (e) {
77-
console.error(` ✗ Failed to install Homebrew: ${e.message}`)
78-
console.error(' Please install manually: https://brew.sh/')
79-
return false
80-
}
81-
}
82-
8351
/**
8452
* Check if binaryen (wasm-opt) is installed.
8553
*/
@@ -93,17 +61,75 @@ async function checkBinaryenInstalled() {
9361
}
9462

9563
/**
96-
* Install binaryen via Homebrew.
64+
* Install binaryen (wasm-opt) cross-platform.
9765
*/
9866
async function installBinaryen() {
67+
const isWindows = process.platform === 'win32'
68+
const isMacOS = process.platform === 'darwin'
69+
const isLinux = process.platform === 'linux'
70+
9971
console.log('📦 Installing binaryen (wasm-opt)...')
72+
console.log(' This may take a few minutes...\\n')
10073

10174
try {
102-
await exec('brew', ['install', 'binaryen'], { stdio: 'inherit' })
103-
console.log(' ✓ binaryen installed successfully\\n')
104-
return true
75+
if (isMacOS) {
76+
// macOS: Try Homebrew first.
77+
console.log(' Trying Homebrew installation...')
78+
try {
79+
await exec('brew', ['--version'])
80+
await exec('brew', ['install', 'binaryen'], { stdio: 'inherit' })
81+
console.log(' ✓ binaryen installed via Homebrew\\n')
82+
return true
83+
} catch {
84+
console.log(' ⚠ Homebrew not available, trying GitHub releases...')
85+
}
86+
} else if (isLinux) {
87+
// Linux: Try apt-get first (Ubuntu/Debian).
88+
console.log(' Trying apt-get installation...')
89+
try {
90+
await exec('sudo', ['apt-get', 'update'], { stdio: 'pipe' })
91+
await exec('sudo', ['apt-get', 'install', '-y', 'binaryen'], { stdio: 'inherit' })
92+
console.log(' ✓ binaryen installed via apt-get\\n')
93+
return true
94+
} catch {
95+
console.log(' ⚠ apt-get not available or failed, trying GitHub releases...')
96+
}
97+
} else if (isWindows) {
98+
// Windows: Try chocolatey first.
99+
console.log(' Trying Chocolatey installation...')
100+
try {
101+
await exec('choco', ['--version'])
102+
await exec('choco', ['install', 'binaryen', '-y'], { stdio: 'inherit' })
103+
console.log(' ✓ binaryen installed via Chocolatey\\n')
104+
return true
105+
} catch {
106+
console.log(' ⚠ Chocolatey not available, trying GitHub releases...')
107+
}
108+
}
109+
110+
// Fallback: Download from GitHub releases (all platforms).
111+
console.log(' Downloading pre-built binaryen from GitHub...')
112+
const version = 'version_119' // Latest stable as of implementation.
113+
let platformSuffix = ''
114+
115+
if (isWindows) {
116+
platformSuffix = 'x86_64-windows'
117+
} else if (isMacOS) {
118+
platformSuffix = process.arch === 'arm64' ? 'arm64-macos' : 'x86_64-macos'
119+
} else if (isLinux) {
120+
platformSuffix = 'x86_64-linux'
121+
}
122+
123+
const url = `https://github.com/WebAssembly/binaryen/releases/download/${version}/binaryen-${version}-${platformSuffix}.tar.gz`
124+
console.log(` URL: ${url}`)
125+
126+
// For CI/automation, we'll gracefully degrade if GitHub releases download fails.
127+
console.log(' ⚠ GitHub releases download not yet implemented')
128+
console.log(' ⚠ wasm-opt will be skipped (install manually for smaller bundles)')
129+
return false
105130
} catch (e) {
106131
console.error(` ✗ Failed to install binaryen: ${e.message}`)
132+
console.error(' ⚠ wasm-opt will be skipped (install manually for optimal bundle size)')
107133
return false
108134
}
109135
}
@@ -141,25 +167,11 @@ const hasBinaryen = await checkBinaryenInstalled()
141167
if (!hasBinaryen) {
142168
console.log('❌ binaryen (wasm-opt) not found\n')
143169

144-
// Check if Homebrew is installed.
145-
const hasBrew = await checkBrewInstalled()
146-
if (!hasBrew) {
147-
console.log('❌ Homebrew not found\n')
148-
const brewInstalled = await installBrew()
149-
if (!brewInstalled) {
150-
console.error(
151-
'⚠ Skipping wasm-opt optimization (install manually for smaller bundle)',
152-
)
153-
}
154-
}
155-
156-
if (hasBrew || (await checkBrewInstalled())) {
157-
const binaryenInstalled = await installBinaryen()
158-
if (!binaryenInstalled) {
159-
console.error(
160-
'⚠ Skipping wasm-opt optimization (install manually for smaller bundle)',
161-
)
162-
}
170+
const binaryenInstalled = await installBinaryen()
171+
if (!binaryenInstalled) {
172+
console.log(
173+
'⚠ wasm-opt not available - bundle will be slightly larger\n',
174+
)
163175
}
164176
} else {
165177
console.log('✓ binaryen (wasm-opt) found\n')

scripts/wasm/check-rust-toolchain.mjs

Lines changed: 74 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -72,52 +72,90 @@ async function checkRustInstalled() {
7272
}
7373

7474
/**
75-
* Install Rust via rustup.
75+
* Install Rust via rustup (cross-platform).
7676
*/
7777
async function installRust() {
7878
console.log('📦 Installing Rust toolchain via rustup...')
7979
console.log(' This may take a few minutes...\n')
8080

81-
const rustupUrl = 'https://sh.rustup.rs'
81+
const isWindows = WIN32
8282

8383
try {
84-
// Download rustup installer.
85-
console.log(` Downloading rustup from ${rustupUrl}...`)
86-
const response = await fetch(rustupUrl)
87-
if (!response.ok) {
88-
throw new Error(`Failed to download rustup: ${response.statusText}`)
89-
}
90-
91-
const script = await response.text()
92-
93-
// Save to temp file.
94-
const tmpDir = path.join(CARGO_HOME, '.tmp')
95-
await fs.mkdir(tmpDir, { recursive: true })
96-
const scriptPath = path.join(tmpDir, 'rustup-init.sh')
97-
await fs.writeFile(scriptPath, script, 'utf-8')
98-
99-
// Run installer.
100-
console.log(' Running rustup installer...')
101-
const result = await exec(
102-
'sh',
103-
[scriptPath, '-y', '--default-toolchain', 'stable'],
104-
{
105-
stdio: 'inherit',
106-
env: {
107-
...process.env,
108-
CARGO_HOME,
109-
RUSTUP_HOME:
110-
process.env.RUSTUP_HOME || path.join(homedir(), '.rustup'),
84+
if (isWindows) {
85+
// Windows: Download and run rustup-init.exe.
86+
const rustupUrl = 'https://win.rustup.rs/x86_64'
87+
console.log(` Downloading rustup-init.exe from ${rustupUrl}...`)
88+
89+
const response = await fetch(rustupUrl)
90+
if (!response.ok) {
91+
throw new Error(`Failed to download rustup: ${response.statusText}`)
92+
}
93+
94+
const buffer = await response.arrayBuffer()
95+
96+
const tmpDir = path.join(CARGO_HOME, '.tmp')
97+
await fs.mkdir(tmpDir, { recursive: true })
98+
const exePath = path.join(tmpDir, 'rustup-init.exe')
99+
await fs.writeFile(exePath, Buffer.from(buffer))
100+
101+
console.log(' Running rustup-init.exe...')
102+
const result = await exec(
103+
exePath,
104+
['-y', '--default-toolchain', 'stable', '--default-host', 'x86_64-pc-windows-msvc'],
105+
{
106+
stdio: 'inherit',
107+
env: {
108+
...process.env,
109+
CARGO_HOME,
110+
RUSTUP_HOME:
111+
process.env.RUSTUP_HOME || path.join(homedir(), '.rustup'),
112+
},
113+
},
114+
)
115+
116+
if (result.code !== 0) {
117+
throw new Error('rustup installation failed')
118+
}
119+
120+
await fs.unlink(exePath)
121+
} else {
122+
// Linux/macOS: Download and run shell script.
123+
const rustupUrl = 'https://sh.rustup.rs'
124+
console.log(` Downloading rustup from ${rustupUrl}...`)
125+
126+
const response = await fetch(rustupUrl)
127+
if (!response.ok) {
128+
throw new Error(`Failed to download rustup: ${response.statusText}`)
129+
}
130+
131+
const script = await response.text()
132+
133+
const tmpDir = path.join(CARGO_HOME, '.tmp')
134+
await fs.mkdir(tmpDir, { recursive: true })
135+
const scriptPath = path.join(tmpDir, 'rustup-init.sh')
136+
await fs.writeFile(scriptPath, script, 'utf-8')
137+
138+
console.log(' Running rustup installer...')
139+
const result = await exec(
140+
'sh',
141+
[scriptPath, '-y', '--default-toolchain', 'stable'],
142+
{
143+
stdio: 'inherit',
144+
env: {
145+
...process.env,
146+
CARGO_HOME,
147+
RUSTUP_HOME:
148+
process.env.RUSTUP_HOME || path.join(homedir(), '.rustup'),
149+
},
111150
},
112-
},
113-
)
151+
)
114152

115-
if (result.code !== 0) {
116-
throw new Error('rustup installation failed')
117-
}
153+
if (result.code !== 0) {
154+
throw new Error('rustup installation failed')
155+
}
118156

119-
// Cleanup.
120-
await fs.unlink(scriptPath)
157+
await fs.unlink(scriptPath)
158+
}
121159

122160
console.log(' ✓ Rust installed successfully\n')
123161
return true

0 commit comments

Comments
 (0)