Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 6 additions & 13 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,32 +30,25 @@ 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

- 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
Expand Down
8 changes: 2 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -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/
37 changes: 18 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 `/<repo>/`), 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 `/<repo>/`), and publishes `app/dist` to
Pages. Enable Pages → "GitHub Actions" in the repo settings once.

## Scope

Expand Down
8 changes: 7 additions & 1 deletion app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 2 additions & 4 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
3 changes: 3 additions & 0 deletions app/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 }[] = [
Expand Down Expand Up @@ -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<ProjectShape>(
{ cmd: "describeProject", files: project() },
{ schemas: [] },
Expand Down
19 changes: 11 additions & 8 deletions app/src/sim/sim-wasm-script.d.ts
Original file line number Diff line number Diff line change
@@ -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;
}
16 changes: 9 additions & 7 deletions app/src/sim/sim-wasm.test.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
/// 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";
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
Expand Down
14 changes: 9 additions & 5 deletions app/src/sim/ui/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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<boolean> {
Expand Down
17 changes: 12 additions & 5 deletions app/src/sim/view.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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);
Expand Down
23 changes: 0 additions & 23 deletions sim-wasm/Cargo.toml

This file was deleted.

6 changes: 0 additions & 6 deletions sim-wasm/src/lib.rs

This file was deleted.

Loading