Skip to content

Commit cd2817e

Browse files
fix: replace wasm-pack with pinned wasm-bindgen-cli in dev setup
The Lua WASM build requires -Zbuild-std which wasm-pack doesn't support, so the build switched to cargo build + wasm-bindgen CLI directly. This updates developer tooling to match: - cargo dev-setup: installs wasm-bindgen-cli@0.2.108 instead of wasm-pack; version-checks the installed binary and reinstalls if it doesn't match the pinned version (wrong version = hard build error at schema mismatch) - build-wasm.js: pre-flight check reads expected version from Cargo.lock and exits early with a clear actionable error if the CLI version differs - CONTRIBUTING.md: document wasm-bindgen-cli requirement, version pinning note, and macOS Homebrew LLVM prerequisite for WASM builds
1 parent e8516d1 commit cd2817e

4 files changed

Lines changed: 129 additions & 23 deletions

File tree

CONTRIBUTING.md

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,33 @@
88

99
The repo includes a `rust-toolchain.toml` that auto-installs the correct nightly toolchain, components (rustfmt, clippy), and the `wasm32-unknown-unknown` target on your first `cargo` invocation. No manual `rustup` steps needed.
1010

11-
### Development tools (cargo-nextest, wasm-pack)
11+
### Development tools (cargo-nextest, wasm-bindgen-cli)
1212

13-
This project uses [nextest](https://nexte.st/) instead of `cargo test`, and [wasm-pack](https://rustwasm.github.io/wasm-pack/) for building WASM modules. Install both with:
13+
This project uses [nextest](https://nexte.st/) instead of `cargo test`, and
14+
[wasm-bindgen-cli](https://rustwasm.github.io/wasm-bindgen/) for building WASM modules. Install both with:
1415

1516
```bash
1617
cargo dev-setup
1718
```
1819

1920
This detects already-installed tools and skips them. When [cargo-binstall](https://github.com/cargo-bins/cargo-binstall) is available, it downloads pre-built binaries (seconds); otherwise it falls back to `cargo install --locked` (slower, compiles from source).
2021

22+
> **Note:** `wasm-bindgen-cli` must exactly match the `wasm-bindgen` crate version pinned in
23+
> `crates/wasm-quarto-hub-client/Cargo.lock`. `cargo dev-setup` installs the correct pinned version
24+
> automatically. If you install it manually, use the version shown in that `Cargo.lock`
25+
> (currently `0.2.108`): `cargo install wasm-bindgen-cli --version 0.2.108`.
26+
> Running `npm run build:all` will tell you if there's a version mismatch.
27+
28+
### macOS: Homebrew LLVM (for WASM builds)
29+
30+
The WASM build compiles Lua C source for `wasm32-unknown-unknown`, which requires LLVM clang — Apple's built-in clang does not support that target.
31+
32+
```bash
33+
brew install llvm
34+
```
35+
36+
This only needs to be done once. The build scripts locate it automatically in the standard Homebrew paths (`/opt/homebrew/opt/llvm` on Apple Silicon, `/usr/local/opt/llvm` on Intel).
37+
2138
### Pandoc 3.6+ (optional)
2239

2340
Four tests in the `pampa` crate compare output against Pandoc. These tests require Pandoc 3.6 or later and will fail when Pandoc is missing or too old. `cargo dev-setup` checks this and warns if needed.

crates/xtask/src/dev_setup.rs

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,53 @@ struct Tool {
1414
/// Command and args to check if the tool is installed.
1515
check_cmd: &'static str,
1616
check_args: &'static [&'static str],
17+
/// If set, the tool must report exactly this version string (matched as a
18+
/// substring of its `--version` output). A wrong version is treated the
19+
/// same as "not installed" and the pinned version is (re-)installed.
20+
required_version: Option<&'static str>,
1721
}
1822

1923
const TOOLS: &[Tool] = &[
2024
Tool {
2125
package: "cargo-nextest",
2226
check_cmd: "cargo",
2327
check_args: &["nextest", "--version"],
28+
required_version: None,
2429
},
30+
// wasm-bindgen-cli must exactly match the wasm-bindgen crate version locked
31+
// in crates/wasm-quarto-hub-client/Cargo.lock. A version mismatch produces
32+
// a hard build error ("schema version … must exactly match").
2533
Tool {
26-
package: "wasm-pack",
27-
check_cmd: "wasm-pack",
34+
package: "wasm-bindgen-cli",
35+
check_cmd: "wasm-bindgen",
2836
check_args: &["--version"],
37+
required_version: Some("0.2.108"),
2938
},
3039
];
3140

3241
fn is_installed(tool: &Tool) -> bool {
33-
Command::new(tool.check_cmd)
34-
.args(tool.check_args)
35-
.stdout(std::process::Stdio::null())
36-
.stderr(std::process::Stdio::null())
37-
.status()
38-
.is_ok_and(|s| s.success())
42+
let output = Command::new(tool.check_cmd).args(tool.check_args).output();
43+
44+
let Ok(output) = output else { return false };
45+
if !output.status.success() {
46+
return false;
47+
}
48+
49+
if let Some(required) = tool.required_version {
50+
let stdout = String::from_utf8_lossy(&output.stdout);
51+
let stderr = String::from_utf8_lossy(&output.stderr);
52+
let combined = format!("{stdout}{stderr}");
53+
if !combined.contains(required) {
54+
let found = combined.lines().next().unwrap_or("unknown").trim();
55+
println!(
56+
" {} — wrong version installed ({found}), need {required}",
57+
tool.package
58+
);
59+
return false;
60+
}
61+
}
62+
63+
true
3964
}
4065

4166
fn has_binstall() -> bool {
@@ -47,28 +72,41 @@ fn has_binstall() -> bool {
4772
.is_ok_and(|s| s.success())
4873
}
4974

50-
fn install(package: &str, use_binstall: bool) -> Result<()> {
75+
fn install(tool: &Tool, use_binstall: bool) -> Result<()> {
76+
let package = tool.package;
77+
// Build the versioned package spec, e.g. "wasm-bindgen-cli@0.2.108"
78+
let versioned = tool
79+
.required_version
80+
.map(|v| format!("{package}@{v}"))
81+
.unwrap_or_else(|| package.to_string());
82+
5183
if use_binstall {
52-
println!(" Installing {package} via cargo binstall...");
84+
println!(" Installing {versioned} via cargo binstall...");
5385
let status = Command::new("cargo")
54-
.args(["binstall", "--no-confirm", package])
86+
.args(["binstall", "--no-confirm", &versioned])
5587
.status()
56-
.with_context(|| format!("Failed to run cargo binstall {package}"))?;
88+
.with_context(|| format!("Failed to run cargo binstall {versioned}"))?;
5789

5890
if status.success() {
5991
return Ok(());
6092
}
6193
println!(" binstall failed, falling back to cargo install...");
6294
}
6395

64-
println!(" Installing {package} via cargo install...");
96+
let mut args = vec!["install", "--locked"];
97+
if let Some(v) = tool.required_version {
98+
args.extend(["--version", v]);
99+
}
100+
args.push(package);
101+
102+
println!(" Installing {versioned} via cargo install...");
65103
let status = Command::new("cargo")
66-
.args(["install", "--locked", package])
104+
.args(&args)
67105
.status()
68-
.with_context(|| format!("Failed to run cargo install {package}"))?;
106+
.with_context(|| format!("Failed to run cargo install {versioned}"))?;
69107

70108
if !status.success() {
71-
bail!("Failed to install {package}");
109+
bail!("Failed to install {versioned}");
72110
}
73111

74112
Ok(())
@@ -90,7 +128,7 @@ pub fn run() -> Result<()> {
90128
println!(" {} — already installed", tool.package);
91129
already += 1;
92130
} else {
93-
install(tool.package, use_binstall)?;
131+
install(tool, use_binstall)?;
94132
installed += 1;
95133
}
96134
}

crates/xtask/src/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
//! ```
77
//!
88
//! Available commands:
9-
//! - `dev-setup`: Install required development tools (cargo-nextest, wasm-pack)
9+
//! - `dev-setup`: Install required development tools (cargo-nextest, wasm-bindgen-cli)
1010
//! - `lint`: Run custom lint checks on the codebase
1111
//! - `test`: Run workspace tests with platform-appropriate crate exclusions
1212
//! - `verify`: Run full project verification (build + tests for Rust and hub-client)
@@ -32,7 +32,7 @@ struct Cli {
3232
enum Command {
3333
/// Install required development tools.
3434
///
35-
/// Checks for cargo-nextest and wasm-pack, installing any that are missing.
35+
/// Checks for cargo-nextest and wasm-bindgen-cli (pinned version), installing any that are missing.
3636
/// Uses cargo-binstall for faster binary installs when available,
3737
/// falling back to cargo install --locked otherwise.
3838
DevSetup {},

hub-client/scripts/build-wasm.js

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
* - Homebrew LLVM (macOS): `brew install llvm`
1313
*/
1414

15-
import { spawn } from 'child_process';
16-
import { existsSync, mkdirSync, rmSync } from 'fs';
15+
import { spawn, spawnSync } from 'child_process';
16+
import { existsSync, mkdirSync, readFileSync, rmSync } from 'fs';
1717
import { dirname, join, resolve } from 'path';
1818
import { fileURLToPath } from 'url';
1919
import { platform } from 'os';
@@ -57,7 +57,58 @@ function run(cmd, args, opts = {}) {
5757
});
5858
}
5959

60+
/**
61+
* Read the wasm-bindgen version locked in the wasm crate's Cargo.lock.
62+
* Returns a string like "0.2.108", or null if it can't be determined.
63+
*/
64+
function lockedWasmBindgenVersion() {
65+
try {
66+
const lockPath = join(wasmCrate, 'Cargo.lock');
67+
const text = readFileSync(lockPath, 'utf-8');
68+
const match = text.match(/name = "wasm-bindgen"\nversion = "([^"]+)"/);
69+
return match ? match[1] : null;
70+
} catch {
71+
return null;
72+
}
73+
}
74+
75+
/**
76+
* Verify that the installed wasm-bindgen CLI matches the version locked in
77+
* Cargo.lock. The versions must match exactly — a mismatch causes a hard
78+
* build error ("schema version … must exactly match").
79+
*/
80+
function checkWasmBindgenVersion() {
81+
const expected = lockedWasmBindgenVersion();
82+
if (!expected) {
83+
console.warn('Warning: could not read wasm-bindgen version from Cargo.lock');
84+
return;
85+
}
86+
87+
const result = spawnSync('wasm-bindgen', ['--version'], { encoding: 'utf-8' });
88+
if (result.error || result.status !== 0) {
89+
console.error('Error: wasm-bindgen CLI not found.');
90+
console.error(`Install the pinned version with:`);
91+
console.error(` cargo install -f wasm-bindgen-cli --version ${expected}`);
92+
console.error('Or run: cargo dev-setup');
93+
process.exit(1);
94+
}
95+
96+
const installed = (result.stdout || result.stderr || '').trim();
97+
if (!installed.includes(expected)) {
98+
console.error(`Error: wasm-bindgen version mismatch.`);
99+
console.error(` installed: ${installed}`);
100+
console.error(` required: wasm-bindgen ${expected} (from Cargo.lock)`);
101+
console.error('');
102+
console.error('The CLI version must exactly match the wasm-bindgen crate version.');
103+
console.error(`Fix with:`);
104+
console.error(` cargo install -f wasm-bindgen-cli --version ${expected}`);
105+
console.error('Or run: cargo dev-setup');
106+
process.exit(1);
107+
}
108+
}
109+
60110
async function buildWasm() {
111+
checkWasmBindgenVersion();
61112
console.log('Building wasm-quarto-hub-client...\n');
62113

63114
// Clean pkg/ directory

0 commit comments

Comments
 (0)