docmd provides two browser APIs: the isomorphic compile engine for rendering markdown in the browser, and the dev-mode plugin API for real-time communication with the dev server.

Isomorphic Compile Engine

The same engine that generates static sites in Node.js can run entirely within a web browser. This is ideal for building CMS previews, interactive playgrounds, or embedding documentation into existing web applications.

Installation via CDN

<!-- Core Styles -->
<link rel="stylesheet" href="https://unpkg.com/@docmd/ui/assets/css/docmd-main.css">

<!-- The Isomorphic Engine -->
<script src="https://unpkg.com/@docmd/live/dist/docmd-live.js"></script>

docmd.compile(markdown, config)

Compiles raw Markdown into a full HTML document string using the default docmd layout.

Parameters:

  • markdown (String): The raw Markdown content.
  • config (Object): Configuration overrides (same schema as docmd.config.json).

Returns: Promise<String>: The complete HTML document.

Example: Live Preview

To ensure style isolation, it is recommended to render the output inside an <iframe> using the srcdoc attribute.

const editor = document.getElementById("editor");
const preview = document.getElementById("preview");

async function updatePreview() {
  const html = await docmd.compile(editor.value, {
    "title": "Preview",
    "theme": { "appearance": "light" }
  });
  preview.srcdoc = html;
}

editor.addEventListener("input", updatePreview);

Dev-Mode Plugin API

During docmd dev, a window.docmd global is automatically injected into every page. This API enables real-time communication between browser-side plugin code and server-side action handlers via WebSocket RPC.

Dev Mode Only

The plugin API methods below are only available during docmd dev. They are not included in production builds.

docmd.call(action, payload)

Call a server-side action handler registered by a plugin. Returns a promise that resolves with the handler’s return value.


const threads = await docmd.call("threads:get-threads", {
  "file": "docs/getting-started.md"
});
console.log(threads); 

If the action modifies source files, the page automatically reloads after the promise resolves.

docmd.send(name, data)

Send a fire-and-forget event to the server. No response is returned.


docmd.send("analytics:page-view", {
  "path": window.location.pathname
});

docmd.on(name, callback)

Subscribe to server-pushed events. Returns an unsubscribe function.


const unsub = docmd.on("threads:updated", (data) => {
  console.log("Threads updated:", data);
});


unsub();

docmd.afterReload(name, callback)

Declare a handler that runs after a page reload. If context was stashed with scheduleReload, the callback receives it.

// Restore scroll position after a live-reload
docmd.afterReload('scroll-restore', (ctx) => {
  window.scrollTo(0, ctx.scrollY);
});

docmd.scheduleReload(name, context)

Stash context into sessionStorage for a named afterReload handler. The matching handler fires with this context after the next page reload.


docmd.scheduleReload("scroll-restore", {
  "scrollY": window.scrollY
});

Considerations

  • No File System: The browser engine cannot scan folders. You must provide the navigation array explicitly in the config object if you need a sidebar.
  • Node-Only Plugins: Plugins that rely on Node.js APIs (like Sitemap or LLM text generation) are disabled in the browser environment.
  • WebSocket Connection: The dev-mode API requires an active WebSocket connection to the dev server. It will auto-reconnect with exponential backoff if the connection drops.