Skip to content

kanakkholwal/docvia

Repository files navigation

docvia

A Markdown documentation compiler. docvia turns a directory of Markdown into typed, pre-rendered content for React, Svelte, or any framework with a renderer adapter — and it runs in three modes from one shared compile core:

  • Build — compile the whole tree ahead of time into a typed module graph.
  • Dev — compile in-process inside the framework dev server, recompiling incrementally on every file change.
  • SSR — render a single document per request, on Node or the edge.

All three sit on the same long-lived CompileService (@docvia/runtime), so output is byte-identical regardless of mode. See MODES.md for the full breakdown.

Why docvia

  • IR-based. Markdown is parsed, sanitized, and transformed into an Intermediate Representation once; renderers turn that IR into framework output.
  • Typed frontmatter. Extend the built-in schema with a Zod object and docvia generates a Frontmatter interface for every collection.
  • Incremental. A content-addressed cache skips unchanged files — across builds and, in dev, on every keystroke.
  • Pluggable. Five hook points across the pipeline, plus build-time syntax highlighting that bakes HTML into the IR so no highlighter ships to the browser.
  • Framework adapters. First-party React and Svelte renderers, an in-process Vite plugin, and a Next.js wrapper (webpack + Turbopack).

Install

pnpm add -D @docvia/cli
pnpm add @docvia/renderer-react   # or @docvia/renderer-svelte

Quick start

npx docvia init                  # scaffold docs/ + docvia.config.ts
npx docvia build                 # compile to .docvia/
npx docvia dev                   # watch & recompile incrementally

Minimal docvia.config.ts:

import { defineConfig } from "@docvia/cli";
import { createReactRenderer } from "@docvia/renderer-react";
import { shiki } from "@docvia/plugin-shiki";

export default defineConfig({
  sourceDir: "docs",
  outDir: ".docvia",
  renderer: createReactRenderer(),
  plugins: [shiki({ theme: "github-dark" })],
});

After docvia build, import the generated source:

// Vite resolves a virtual module; Next.js aliases the bare specifier.
import { docs } from "virtual:docvia/source"; // Next.js: "docvia/source"

const page = await docs.getPage(["getting-started"]); // slug segments
const all = docs.getPages();                          // metadata for every page
const tree = docs.pageTree;                           // navigation tree

Framework integration

The recommended setup runs docvia in-process inside your bundler — no separate docvia build step, incremental recompilation in dev, and a virtual source module (virtual:docvia/source on Vite, the aliased docvia/source on Next.js) so nothing is written to disk during development.

SvelteKit (Vite)

pnpm add -D @docvia/plugin-vite @docvia/cli
pnpm add @docvia/renderer-svelte @docvia/source
// vite.config.ts
import { docvia } from "@docvia/plugin-vite";
import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig } from "vite";
import docviaConfig from "./docvia.config";

export default defineConfig({
  plugins: [sveltekit(), docvia(docviaConfig)],
});

docvia() runs the CompileService in-process: it serves virtual:docvia/source (and virtual:docvia/source/browser) as virtual modules in dev with incremental HMR, and serves them from the load hook for production builds too. The config must use the Svelte renderer (createSvelteRenderer from @docvia/renderer-svelte/node). Consume pages in a catch-all route via docs.getPage(...) and render them with the Renderer component from @docvia/renderer-svelte. See examples/demo-svelte and apps/docs for working setups.

Next.js

pnpm add -D @docvia/plugin-next @docvia/cli
pnpm add @docvia/renderer-react @docvia/source react react-dom
// next.config.mjs
import { withDocvia } from "@docvia/plugin-next";

export default withDocvia({ configPath: "./docvia.config.ts" })({
  reactStrictMode: true,
});

withDocvia drives the CompileService when the Next config is evaluated, aliases docvia/source for both webpack and Turbopack, and runs an incremental watcher in dev. See examples/demo-next.

Server-side rendering

Markdown is loaded in place as a module via the ?docvia loader (Vite, webpack, and Turbopack), so a framework app renders pages directly through its renderer — including on the edge — with no separate content store. One module imports the pages eagerly (server/SSR, bundled), another lazily (client, code-split per page):

// Server / SSR (eager). Vite resolves a virtual module; Next.js aliases the
// bare specifier:
import { docs } from "virtual:docvia/source"; // Next.js: "docvia/source"

// Browser (lazy, code-split per page) — aliased so it doesn't clash with the
// eager import above:
import { docs as browserDocs } from "virtual:docvia/source/browser"; // Next.js: "docvia/source/browser"

const page = await docs.getPage(["getting-started"]);
const lazyPage = await browserDocs.getPage(["getting-started"]);

For a non-framework Node server that renders per request, @docvia/ssr renders IR resolved by a content source — a live CompileService already is one, so pass it directly:

import { createDocviaSSR } from "@docvia/ssr";

const ssr = createDocviaSSR({ provider: service }); // or a (collection, slug) => IR fn
const page = await ssr.render("docs", "getting-started");

Rendered pages are cached in an in-memory LRU keyed by content hash.

Standalone preview

docvia preview serves .docvia/ over sirv — a sanity check for the compiled output only. It is not a runtime; use a framework integration for a real site.

Packages

Package Version Purpose
@docvia/cli npm init / build / dev / preview commands.
@docvia/runtime npm CompileService — the stateful compile core shared by build, dev, and SSR.
@docvia/compiler npm Batch build entry (compile()), a thin wrapper over CompileService.
@docvia/core npm Markdown parsing pipeline (unified + remark + rehype).
@docvia/ir npm Intermediate representation, error system, AST → IR transform.
@docvia/schema npm Frontmatter validation (Zod), YAML extraction, TS codegen.
@docvia/plugins npm defineConfig, loadConfig, PluginRunner.
@docvia/ssr npm Request-time rendering for non-framework Node servers.
@docvia/renderer-core npm Framework-agnostic rendering engine and default renderers.
@docvia/renderer-react npm React renderer adapter (server + ./client hydration).
@docvia/renderer-svelte npm Svelte renderer adapter.
@docvia/search npm Section-level Orama indexing and client search helper.
@docvia/source npm Runtime collection model (createCollection / createSource) for the generated source module.
@docvia/plugin-vite npm In-process Vite plugin (docvia()) with virtual modules + HMR.
@docvia/plugin-next npm Next.js wrapper (withDocvia) — webpack + Turbopack.
@docvia/plugin-shiki npm Build-time syntax highlighting via Shiki (pluggable).
@docvia/plugin-openapi npm Generate reference pages from an OpenAPI spec.

Status

v0.2 preview. APIs are stabilizing; expect breaking changes before v1.0. See .changeset/ for in-flight release notes and documentation.md for architecture notes.

Contributing

Contributions are welcome. See CONTRIBUTING.md for the local setup, watch modes, and release workflow.

License

MIT

About

framework agnostic documentation compiler

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors