From 097f11487c8cd640ea537aa91fac0485f805459c Mon Sep 17 00:00:00 2001 From: Kinflou Date: Fri, 4 Sep 2026 02:20:46 +0800 Subject: [PATCH] sim: consume comline-simulator as a git dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drops the `sim-wasm/` wrapper crate. `comline-simulator` (github:ComlineProject/simulator) builds itself to WASM in its `prepare` on `npm install` — `pkg/` (lean) and `pkg-script/` (Rhai) — so there's nothing to wasm-pack here for the sim. - `app/src/sim/ui/view.ts` / tests import from `comline-simulator` and `comline-simulator/pkg-script/comline_simulator.js`; the lazy scripted import still code-splits. - `app/src/main.ts` now `await`s the sim wasm init before entering the simulate view — it was never initialised, so the deployed view has been broken since the TS engine was removed (#37). Tests init explicitly, which is why it went unnoticed. - `deploy.yml` drops the two sim wasm-pack steps (npm install covers them); keeps the editor wasm-pack + a cargo cache for the one-time wasm-bindgen-cli build. 20 view tests + the build pass. Repin the dep to the simulator#17 merge SHA before this lands. --- .github/workflows/deploy.yml | 19 ++++++---------- .gitignore | 8 ++----- README.md | 37 ++++++++++++++++---------------- app/package-lock.json | 8 ++++++- app/package.json | 6 ++---- app/src/main.ts | 3 +++ app/src/sim/sim-wasm-script.d.ts | 19 +++++++++------- app/src/sim/sim-wasm.test.ts | 16 ++++++++------ app/src/sim/ui/view.ts | 14 +++++++----- app/src/sim/view.test.ts | 17 ++++++++++----- sim-wasm/Cargo.toml | 23 -------------------- sim-wasm/src/lib.rs | 6 ------ 12 files changed, 79 insertions(+), 97 deletions(-) delete mode 100644 sim-wasm/Cargo.toml delete mode 100644 sim-wasm/src/lib.rs diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 7edf81c..c7573d0 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -30,9 +30,9 @@ jobs: path: | ~/.cargo/registry ~/.cargo/git + ~/.cargo/bin wasm/target - sim-wasm/target - key: ${{ runner.os }}-cargo-${{ hashFiles('wasm/Cargo.toml', 'sim-wasm/Cargo.toml') }} + key: ${{ runner.os }}-cargo-${{ hashFiles('wasm/Cargo.toml', 'app/package-lock.json') }} - name: Install wasm-pack run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh @@ -40,22 +40,15 @@ jobs: - name: Build editor WASM run: wasm-pack build wasm --release --target web --out-dir ../app/src/wasm --out-name comline_playground_wasm - # The simulation engine (ComlineProject/simulator), lean build — no Rhai - # scripting. - - name: Build sim WASM - run: wasm-pack build sim-wasm --release --target web --out-dir ../app/src/sim-wasm --out-name comline_sim - - # The scripted build (Rhai `script` behaviour, ~4× the wasm). Same crate, - # `--features script`, its own out-dir; the UI code-splits it and fetches - # it on demand. - - name: Build scripted sim WASM - run: wasm-pack build sim-wasm --release --target web --out-dir ../app/src/sim-wasm-script --out-name comline_sim_script -- --features script - - name: Node uses: actions/setup-node@v4 with: node-version: 22 + # `npm install` pulls `comline-simulator` (the sim engine) as a git + # dependency and builds its WASM in `prepare` — lean `pkg/` + scripted + # `pkg-script/`. The runner has cargo + wasm-opt; the cargo cache above + # keeps the one-time wasm-bindgen-cli build. - name: Install working-directory: app run: npm install diff --git a/.gitignore b/.gitignore index 4f9f3c5..00c0ff0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,13 @@ -# Rust +# Rust — the editor wasm crate (the sim engine is an npm git dependency now) /wasm/target -/sim-wasm/target Cargo.lock # Node / Vite node_modules /app/dist -# wasm-pack output (regenerated by `npm run wasm` / `npm run sim-wasm` / -# `npm run sim-wasm:script` / CI) +# wasm-pack output for the editor wasm (regenerated by `npm run wasm` / CI) /app/src/wasm -/app/src/sim-wasm -/app/src/sim-wasm-script .DS_Store .idea/ diff --git a/README.md b/README.md index 9568bf0..389b9a6 100644 --- a/README.md +++ b/README.md @@ -17,40 +17,39 @@ wasm/ comline-playground-wasm — the editor's Rust crate, wasm-bindgen surf semantic_tokens / hover / completions — the LSP handlers verbatim deps: comline-core, comline-codegen, comline-codegen-rust, comline-codegen-typescript, comline-language-server (git rev) -sim-wasm/ a thin wrapper that re-exports ComlineProject/simulator's `Sim` - surface (git rev). `npm run sim-wasm` builds it lean (~520 KB); - `npm run sim-wasm:script` adds the Rhai `script` behaviour (~2.1 MB), - a separate chunk the simulate view fetches only when a `script` - behaviour is picked. app/ a Vite site: a CodeMirror 6 editor (highlighting / diagnostics / hover / autocomplete all from the editor WASM's LSP, in a Web Worker), plus the **simulate** view — a thin canvas / inspector / frame-log over the sim WASM. `app/src/sim/` is that view; the engine - it drives lives in ComlineProject/simulator. -.github/workflows/deploy.yml build the WASMs (editor, sim, scripted sim) - → build site → deploy to Pages + is the `comline-simulator` git dependency (ComlineProject/simulator), + which builds itself to WASM on `npm install` — `pkg/` (lean) plus + `pkg-script/` (Rhai, code-split and fetched only when a `script` + behaviour is picked). +.github/workflows/deploy.yml build editor WASM → npm install (builds the sim + WASM) → build site → deploy to Pages ``` ## Develop ```sh cd app -npm install -npm run dev # editor + lean sim WASM, then Vite -npm run sim-wasm:script # once, if you want to exercise `script` behaviours +npm install # also clones + builds comline-simulator to WASM (needs cargo) +npm run dev # editor WASM, then Vite ``` -`npm run dev` skips the scripted sim WASM (it is slow to build and rarely -touched); without it, picking a `script` behaviour just shows an inspector -notice. `npm run build` *does* need it — run `npm run sim-wasm:script` first, as -CI does. Requires a Rust toolchain with the `wasm32-unknown-unknown` target and -[`wasm-pack`](https://rustwasm.github.io/wasm-pack/). +Needs a Rust toolchain with the `wasm32-unknown-unknown` target (for the editor +WASM via [`wasm-pack`](https://rustwasm.github.io/wasm-pack/), and for +`comline-simulator`'s install-time build — `npm install` compiles +`wasm-bindgen-cli` once, then caches it in `~/.cargo`). `wasm-opt` trims the +output when present. `COMLINE_SIMULATOR_SCRIPT=0 npm install` skips the ~2 MB +scripted build. ## Deploy -Push to `master`. The workflow builds the WASM with `wasm-pack`, builds the site -with Vite (`base: "./"`, so it works under `//`), and publishes `app/dist` -to Pages. Enable Pages → "GitHub Actions" in the repo settings once. +Push to `master`. The workflow builds the editor WASM (`wasm-pack`), runs +`npm install` (which builds `comline-simulator` to WASM), builds the site with +Vite (`base: "./"`, so it works under `//`), and publishes `app/dist` to +Pages. Enable Pages → "GitHub Actions" in the repo settings once. ## Scope diff --git a/app/package-lock.json b/app/package-lock.json index 5f50de5..91d4089 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -18,7 +18,8 @@ "@codemirror/lint": "^6.8.0", "@codemirror/state": "^6.4.0", "@codemirror/view": "^6.34.0", - "@lezer/highlight": "^1.2.3" + "@lezer/highlight": "^1.2.3", + "comline-simulator": "git+https://github.com/ComlineProject/simulator.git#feat/prepare-builds-scripted" }, "devDependencies": { "@types/node": "^20.19.43", @@ -1087,6 +1088,11 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/comline-simulator": { + "version": "0.0.0", + "resolved": "git+ssh://git@github.com/ComlineProject/simulator.git#e83b4f3d5c5f655db5fbcc947a066274e7c9c62a", + "license": "MPL-2.0" + }, "node_modules/crelt": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.7.tgz", diff --git a/app/package.json b/app/package.json index 98acf2b..5958b90 100644 --- a/app/package.json +++ b/app/package.json @@ -5,15 +5,13 @@ "type": "module", "scripts": { "wasm": "wasm-pack build ../wasm --release --target web --out-dir ../app/src/wasm --out-name comline_playground_wasm", - "sim-wasm": "wasm-pack build ../sim-wasm --release --target web --out-dir ../app/src/sim-wasm --out-name comline_sim", - "sim-wasm:script": "wasm-pack build ../sim-wasm --release --target web --out-dir ../app/src/sim-wasm-script --out-name comline_sim_script -- --features script", - "wasm:all": "npm run wasm && npm run sim-wasm", - "dev": "npm run wasm:all && vite", + "dev": "npm run wasm && vite", "build": "tsc --noEmit && vite build", "preview": "vite preview", "test": "tsc -p tsconfig.test.json && node --import tsx --test \"src/sim/**/*.test.ts\"" }, "dependencies": { + "comline-simulator": "git+https://github.com/ComlineProject/simulator.git#feat/prepare-builds-scripted", "@codemirror/autocomplete": "^6.18.0", "@codemirror/commands": "^6.7.0", "@codemirror/lang-javascript": "^6.2.5", diff --git a/app/src/main.ts b/app/src/main.ts index 4762c24..f42e365 100644 --- a/app/src/main.ts +++ b/app/src/main.ts @@ -21,6 +21,8 @@ import type { SemanticTokens, } from "./worker.ts"; import { createSim, type ProjectShape, type SimView } from "./sim/index.ts"; +import initSimWasm from "comline-simulator"; +import simWasmUrl from "comline-simulator/pkg/comline_simulator_bg.wasm?url"; // ── sample: two files, one `use`ing the other ──────────────────────────── const SAMPLE_FILES: { name: string; doc: string }[] = [ @@ -729,6 +731,7 @@ let sim: SimView | null = null; let simLoaded = false; async function enterSimulate() { + await initSimWasm({ module_or_path: simWasmUrl }); // idempotent const shape = await unwrap( { cmd: "describeProject", files: project() }, { schemas: [] }, diff --git a/app/src/sim/sim-wasm-script.d.ts b/app/src/sim/sim-wasm-script.d.ts index 42ed815..eeddeab 100644 --- a/app/src/sim/sim-wasm-script.d.ts +++ b/app/src/sim/sim-wasm-script.d.ts @@ -1,8 +1,11 @@ -// `comline_sim_script.js` (in `app/src/sim-wasm-script/`) is a wasm-pack -// artifact built on demand — by `npm run sim-wasm:script` and the deploy -// workflow, not by `npm run dev`. It exports the same surface as the lean -// `comline_sim.js`, just with the Rhai `script` behaviour compiled in. This -// opaque ambient lets `tsc` resolve the lazy `import()` when the artifact (and -// its generated `.d.ts`) is absent; callers cast the module to the lean -// module's type. -declare module "*/comline_sim_script.js"; +// `comline-simulator/pkg-script/` is the Rhai-enabled build. The engine's +// `prepare` produces it by default on `npm install`, but a consumer can opt out +// (`COMLINE_SIMULATOR_SCRIPT=0`), so these opaque ambients keep `tsc` resolving +// the lazy `import()`s even when that build (and its generated `.d.ts`) is +// absent. Callers cast the module to `typeof import("comline-simulator")`. +declare module "comline-simulator/pkg-script/comline_simulator.js"; + +declare module "comline-simulator/pkg-script/comline_simulator_bg.wasm?url" { + const url: string; + export default url; +} diff --git a/app/src/sim/sim-wasm.test.ts b/app/src/sim/sim-wasm.test.ts index 2561b53..f0726d6 100644 --- a/app/src/sim/sim-wasm.test.ts +++ b/app/src/sim/sim-wasm.test.ts @@ -1,6 +1,6 @@ -/// The engine now lives in `ComlineProject/simulator` (Rust → WASM). This proves -/// the wasm loads through the wrapper crate and its `Sim` surface round-trips a -/// call. The rest of `src/sim/` is being rewired onto it. +/// The engine lives in `ComlineProject/simulator` (Rust → WASM), pulled in as +/// the `comline-simulator` git dependency. This proves the wasm loads and its +/// `Sim` surface round-trips a call. import { readFileSync } from "node:fs"; import { fileURLToPath } from "node:url"; @@ -8,14 +8,16 @@ import { strict as assert } from "node:assert"; import { test } from "node:test"; import initEditor, { describe_project } from "../wasm/comline_playground_wasm.js"; -import initSim, { Sim } from "../sim-wasm/comline_sim.js"; +import initSim, { Sim } from "comline-simulator"; + +const simWasm = fileURLToPath( + new URL("../../node_modules/comline-simulator/pkg/comline_simulator_bg.wasm", import.meta.url), +); await initEditor( readFileSync(fileURLToPath(new URL("../wasm/comline_playground_wasm_bg.wasm", import.meta.url))), ); -await initSim( - readFileSync(fileURLToPath(new URL("../sim-wasm/comline_sim_bg.wasm", import.meta.url))), -); +await initSim(readFileSync(simWasm)); const CHAT = `struct Message { body: string diff --git a/app/src/sim/ui/view.ts b/app/src/sim/ui/view.ts index b540234..cd2776a 100644 --- a/app/src/sim/ui/view.ts +++ b/app/src/sim/ui/view.ts @@ -10,7 +10,7 @@ /// polls `sim.frames()`. import { findProtocol, type ProjectShape, type ThrowShape } from "../shape.ts"; -import { Sim } from "../../sim-wasm/comline_sim.js"; +import { Sim } from "comline-simulator"; import { argsForm, type ArgsForm } from "./argsform.ts"; import { frameLog, type ClockBar, type Frame, type FrameSource, type LogSource } from "./framelog.ts"; @@ -130,11 +130,15 @@ export function createSim(opts: SimOpts = {}): SimView { opts.loadScripted ?? (async () => { // Same surface as the lean module, just Rhai-enabled — hence the cast - // (the ambient for this on-demand artifact is deliberately opaque). + // (the `pkg-script/` ambient is deliberately opaque). Vite code-splits + // this dynamic import, so the ~2 MB scripted wasm only downloads here. const m = (await import( - "../../sim-wasm-script/comline_sim_script.js" - )) as typeof import("../../sim-wasm/comline_sim.js"); - await m.default(); + "comline-simulator/pkg-script/comline_simulator.js" + )) as typeof import("comline-simulator"); + const { default: wasmUrl } = await import( + "comline-simulator/pkg-script/comline_simulator_bg.wasm?url" + ); + await m.default({ module_or_path: wasmUrl }); return { Sim: m.Sim }; }); async function ensureScripted(): Promise { diff --git a/app/src/sim/view.test.ts b/app/src/sim/view.test.ts index c3978c1..ce634c3 100644 --- a/app/src/sim/view.test.ts +++ b/app/src/sim/view.test.ts @@ -21,9 +21,13 @@ const { describe_project } = await import("../wasm/comline_playground_wasm.js"); await initWasm( readFileSync(fileURLToPath(new URL("../wasm/comline_playground_wasm_bg.wasm", import.meta.url))), ); -const initSim = (await import("../sim-wasm/comline_sim.js")).default; +const initSim = (await import("comline-simulator")).default; await initSim( - readFileSync(fileURLToPath(new URL("../sim-wasm/comline_sim_bg.wasm", import.meta.url))), + readFileSync( + fileURLToPath( + new URL("../../node_modules/comline-simulator/pkg/comline_simulator_bg.wasm", import.meta.url), + ), + ), ); const { createSim } = await import("./ui/view.ts"); import type { ProjectShape } from "./shape.ts"; @@ -783,17 +787,20 @@ test("2e — record a call through the UI, then replay it", async () => { // ── 2f — scripted behaviour (Rhai), lazy-loaded ────────────────────── const scriptedWasm = fileURLToPath( - new URL("../sim-wasm-script/comline_sim_script_bg.wasm", import.meta.url), + new URL( + "../../node_modules/comline-simulator/pkg-script/comline_simulator_bg.wasm", + import.meta.url, + ), ); const loadScripted = async () => { - const m = await import("../sim-wasm-script/comline_sim_script.js"); + const m = await import("comline-simulator/pkg-script/comline_simulator.js"); await m.default(readFileSync(scriptedWasm)); return { Sim: m.Sim }; }; test( "2f — picking `script` pulls the scripted wasm and runs a Rhai reply", - { skip: existsSync(scriptedWasm) ? false : "run `npm run sim-wasm:script` first" }, + { skip: existsSync(scriptedWasm) ? false : "set COMLINE_SIMULATOR_SCRIPT=1 and reinstall" }, async () => { const sim = createSim({ loadScripted }); document.body.append(sim.el); diff --git a/sim-wasm/Cargo.toml b/sim-wasm/Cargo.toml deleted file mode 100644 index 2471601..0000000 --- a/sim-wasm/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "comline-playground-sim-wasm" -version = "0.1.0" -edition = "2021" -license = "GPL-3.0-only" -publish = false - -[lib] -crate-type = ["cdylib", "rlib"] - -[dependencies] -# The simulation engine — its own repo, pinned by rev, the same pattern `wasm/` -# uses for `comline-core`. Default build is lean (no Rhai); `--features script` -# is a separate, lazily-loaded artifact. -comline-simulator = { git = "https://github.com/ComlineProject/simulator", rev = "de5dc5e0c64081695f15466db91c131254ed2f37", default-features = false } -wasm-bindgen = "0.2" - -[features] -script = ["comline-simulator/script"] - -[profile.release] -opt-level = "s" -lto = true diff --git a/sim-wasm/src/lib.rs b/sim-wasm/src/lib.rs deleted file mode 100644 index bfa7137..0000000 --- a/sim-wasm/src/lib.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! Thin wrapper: re-export `comline-simulator`'s `#[wasm_bindgen]` surface so -//! `wasm-pack build sim-wasm` produces the playground's sim module. The engine -//! lives in `ComlineProject/simulator`; this crate only pins its rev and picks -//! the `script` feature on or off. - -pub use comline_simulator::*;