Dev mode (@sigx/terminal-dev)
@sigx/terminal-dev is an HMR dev runner for SignalX terminal apps. Run your TUI under an in-process Vite dev server, save a component file, and watch the running terminal app update in place — no restart, no lost state.
pnpm add -D @sigx/terminal-devRunning an app
The package installs a sigx-terminal-dev binary:
sigx-terminal-dev # auto-detect src/main.tsx and similar
sigx-terminal-dev src/main.tsx # point at the mount module
sigx-terminal-dev --root path/to/app
sigx-terminal-dev --config vite.config.ts # layer your own Vite config on top
Point it at the module that mounts your app:
/** @jsxImportSource @sigx/runtime-core */
// src/main.tsx — the "mount module"
import { defineApp, terminalMount } from '@sigx/terminal';
import { App } from './App';
defineApp(<App />).mount({ fullscreen: true }, terminalMount);
Your tsconfig.json needs the usual SignalX JSX setup ("jsx": "react-jsx" and "jsxImportSource": "@sigx/runtime-core", or the @sigx/terminal facade — see Installation).
What a save does
- Edit a component module (a file that calls
component(...), likeApp.tsx): just that module re-executes. Every live instance re-runs the new setup against its existing context and re-renders in place. The terminal never tears down, and state outside the edited setup — parent components, stores, module-level signals elsewhere — survives. - Edit the mount module (or a module nothing accepts): the app restarts in-process — clean terminal teardown, module cache dropped, entry re-imported.
- Break the build: the error is reported (above the live region while mounted); the next successful save recovers automatically.
- Quit with Ctrl+C: the dev process exits
0. Quitting the app is the normal end of a dev session, so wrappers like pnpm scripts don't report a failure. (Raw mode delivers Ctrl+C to the app as a key; the app's conventional exit 130 is translated by the bin, and other exit codes pass through.)
Programmatic API
For embedding the dev runner in your own tooling:
import { startDev } from '@sigx/terminal-dev';
const handle = await startDev({
entry: 'src/main.tsx',
root: process.cwd(),
onError: (err) => { /* entry failed to (re)start */ },
onRestart: () => { /* entry (re)started */ },
});
// handle.server — the ViteDevServer
// handle.runner — the Vite ModuleRunner
await handle.restart(); // manual in-process restart
await handle.close();
For a custom Vite setup, use terminalDevPlugin() — the Vite plugin that injects HMR identity registration and self-accept into component modules and keeps @sigx/* external for SSR. The HMR runtime that patches live instances lives at @sigx/terminal-dev/hmr and is injected automatically.
How it works
- An in-process Vite dev server (middleware mode, silent) plus a module runner executes the app in Node.
@sigx/*packages stay out of the hot graph wherever possible, so the renderer's terminal state and the reactivity instance survive hot updates. - The plugin gives every
component(...)definition a stable identity (moduleId:index). When an edited module re-executes, the HMR runtime re-runs the new setup with each live instance's existing context, swapsctx.renderFn, and callsctx.update()— the contract@sigx/runtime-coreexposes for HMR. Factories previously defined under the same identity are repointed at the new setup too, so parents that captured a component reference before the edit (tab catalogs, navigation) mount the new code on the next visit. - Mount modules (those calling
defineApp/renderTerminal/mountTerminal) never self-accept — re-executing one would mount a second app — so edits there surface as a full reload, which the runner intercepts: tear down the terminal, clear the module cache, re-import the entry.
Limitations
These are inherent to setup-rerun HMR:
- Signals created inside the edited component's setup are re-created (their state resets); state anywhere else survives.
onMounteddoes not re-fire for already-mounted instances on a hot update.
Peer dependency
@sigx/terminal-dev lists @sigx/runtime-core (0.6.x) as a peer dependency and bundles Vite. Install it as a dev dependency.
Next steps
- Installation — the TSX/Vite config dev mode expects.
- Render modes —
terminalMountand the mount options. - Architecture — where
terminal-devsits in the stack.
