hmr-serve
v0.1.3
Published
Point at any folder and review it live in the browser — VSCode-style file tree + content pane, powered by Vite's dev server and HMR client.
Maintainers
Readme
hmr-serve
Point hmr-serve at any folder and review it live in the browser: a VSCode-style
file tree on the left, a content pane on the right, and instant updates as files
change on disk — powered by Vite's real dev server and
HMR client, not a
hand-rolled watcher/websocket.
HMR (Hot Module Replacement) is the mechanism that pushes file changes into the browser over a WebSocket so the page updates without a full refresh. This project uses Vite's HMR rather than inventing its own.
Tip: Helpful for reviewing AI agent output (markdown/HTML docs) as it iterates.
Quickstart
npx hmr-serve ./some-folder
# → opens http://localhost:5183 with a live tree + content paneOr run it like serve without the nav — serves directory
listing or index.html if present, plus rendered Markdown, CSV/TSV, all with HMR:
npx hmr-serve ./some-folder --no-navFor a permanent setup, install globally and use the short hmr command:
npm install -g hmr-serve
hmr ./some-folder
hmr ./some-folder --no-navCLI:
hmr [dir] Folder to serve (default: current directory)
--port <port> Port to listen on (default: 5183)
--open Open the browser on start
--no-nav Like serve, without the tree UIDefault (nav) mode shows a VS Code-style file tree and content pane. Supported
types: Markdown (rendered), HTML (sandboxed iframe), code (.css,
.js, .ts, .json, … syntax-highlighted), text, CSV/TSV (tables),
images, and video. A gear menu toggles which categories show in the tree,
plus an Other files option. Choices are remembered per folder (localStorage).
--no-nav skips the tree UI: if the folder has index.html (or index.htm),
that is the root page; otherwise you get a directory listing. Markdown, CSV, and
TSV are still rendered to HTML, and edits hot-reload via Vite.
Architecture
- No build step for your content. Runs in Vite dev-server mode only. The app
shell (a tiny Vue UI) is Vite's root; your folder is mounted alongside it via
middleware +
server.fs.allow. Your files are the content — nothing is compiled. - Live search index. Built at startup with MiniSearch (no native deps) and kept current incrementally off file-watch events — no rebuild step.
- Plain HTTP + WebSocket, cross-browser. The browser only talks to the Node server over HTTP and Vite's HMR socket. No File System Access API, no Chromium-only APIs — works in Safari and Firefox.
- Extensible renderer registry.
.md→markdown-it;.html→ sandboxed iframe;.css/.txt→ server-sidehighlight.js;.csv/.tsv→ HTML tables styled with GitHub markdown CSS. New types register insrc/server/renderers/without touching routing. - Lightweight CLI via
cac:<path>,--port,--open,--no-nav.
Live content updates ride Vite's HMR channel: the server pushes a custom
hmr-serve:update event and the content pane re-fetches — so Vite's client
handles transport and reconnection for us.
Links & URLs. Raw HTML is served at mirror paths (/__hmrserve/raw/<file>),
so relative links and assets inside a framed doc (href="contact.html",
<img src="logo.png">) resolve against the real folder layout. The selected file
is reflected in a clean, bookmarkable URL under the served folder's name — e.g.
serving ./aurora-notes gives /aurora-notes/docs/intro.md. These are real
History-API paths (no #): shareable, reload-safe, and back/forward works.
Unknown paths 404 rather than rendering the app, so a stray absolute link can't
nest the shell inside the content pane.
src/
cli/ arg parsing + entry
server/ Vite plugin, middleware, search index, watcher, renderers
client/ Vue app shell (tree + content pane)
shared/ types shared across server and client
fixtures/ versioned sample files used by tests
tests/ unit · component · e2eContributing
See CONTRIBUTING.md for local setup and test expectations.
