Svelte 5 + Vite-powered documentation engine. Write Markdown, get a beautiful documentation site — hot-reloaded in milliseconds.
Inspired by VitePress{target="_blank"}, built on Svelte 5.
npx @dominikcz/greg initFor unattended/default setup (no prompts):
npx @dominikcz/greg init --defaultsThe interactive wizard asks for docs path, site title, TypeScript preference, config mode (minimal or full), and starter docs type (empty, sample, or generated fake docs). It also creates a sensible .gitignore, copies default public/ assets, and can install all required dependencies for you.
At the end you only need:
npm run devIn this repository, prefer npm run ... scripts for development.
In consumer projects using Greg, use greg ... (typically via npm scripts) or npx greg ....
npm install --save-dev @dominikcz/greg @sveltejs/vite-plugin-svelte svelte viteIf your package.json does not already define module type, set:
{
"type": "module"
}vite.config.js
import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'
import {
vitePluginGregConfig,
vitePluginSearchIndex,
vitePluginSearchServer,
vitePluginAiServer,
vitePluginFrontmatter,
vitePluginCopyDocs,
} from '@dominikcz/greg/plugins'
export default defineConfig({
plugins: [
svelte(),
vitePluginGregConfig(),
vitePluginSearchIndex({ docsDir: 'docs', srcDir: '/' }),
vitePluginSearchServer({ docsDir: 'docs', srcDir: '/' }),
vitePluginAiServer({ docsDir: 'docs', srcDir: '/' }),
vitePluginFrontmatter({ docsDir: 'docs', srcDir: '/' }),
vitePluginCopyDocs({ docsDir: 'docs', srcDir: '/' }),
],
})svelte.config.js (must be .js — not .ts)
export { default } from '@dominikcz/greg/svelte.config'greg.config.js (or .ts)
/** @type {import('@dominikcz/greg').GregConfig} */
export default {
srcDir: 'docs',
docsBase: '',
mainTitle: 'My Docs',
shiki: {
extraLangs: ['python', 'sql', 'csharp', 'pascal'],
},
sidebar: [
{ text: 'Guide', auto: '/guide' },
{ text: 'GitHub', link: 'https://github.com/dominikcz/greg' }, // default: _self
{ text: 'GitHub (new tab)', link: 'https://github.com/dominikcz/greg', target: '_blank' },
],
}src/App.svelte
<script>
import MarkdownDocs from '@dominikcz/greg'
</script>
<MarkdownDocs />Greg supports VitePress-style locales in greg.config.js.
- Locale keys use paths like
'/','/pl/','/de/' - They are resolved under
docsBase(URL prefix) - Supported per locale:
lang,title,label - Supported per locale
themeConfigkeys:nav,sidebar,outline,lastUpdatedText,langMenuLabel,sidebarMenuLabel,skipToContentLabel,returnToTopLabel,darkModeSwitchLabel,lightModeSwitchTitle,darkModeSwitchTitle,docFooter,siteTitle,logo,socialLinks,editLink,footer,aside,lastUpdated - Header automatically shows a language switcher when at least two locales are configured
i18nRouting: true(default) keeps the same relative page when possiblei18nRouting: falseswitches directly to locale root
/** @type {import('@dominikcz/greg').GregConfig} */
export default {
srcDir: 'docs',
docsBase: '',
i18nRouting: true,
locales: {
'/': {
lang: 'en-US',
title: 'My Docs',
themeConfig: {
nav: [
{ text: 'Guide', link: '/guide' },
{ text: 'Reference', link: '/reference' },
],
sidebar: [
{ text: 'Guide', auto: '/guide' },
{ text: 'Reference', auto: '/reference' },
],
outline: [2, 3],
lastUpdatedText: 'Last updated:',
langMenuLabel: 'Change language',
sidebarMenuLabel: 'Menu',
skipToContentLabel: 'Skip to content',
returnToTopLabel: 'Return to top',
darkModeSwitchLabel: 'Appearance',
lightModeSwitchTitle: 'Switch to light theme',
darkModeSwitchTitle: 'Switch to dark theme',
docFooter: { prev: 'Previous', next: 'Next' },
},
},
'/pl/': {
lang: 'pl-PL',
label: 'Polski',
title: 'Moje Dokumenty',
themeConfig: {
nav: [
{ text: 'Przewodnik', link: '/pl/guide' },
{ text: 'Referencja', link: '/pl/reference' },
],
sidebar: [
{ text: 'Przewodnik', auto: '/pl/guide' },
{ text: 'Referencja', auto: '/pl/reference' },
],
outline: { level: [2, 3], label: 'Na tej stronie' },
lastUpdatedText: 'Zaktualizowano:',
langMenuLabel: 'Zmien jezyk',
sidebarMenuLabel: 'Menu',
skipToContentLabel: 'Przejdz do tresci',
returnToTopLabel: 'Wroc na gore',
darkModeSwitchLabel: 'Wyglad',
lightModeSwitchTitle: 'Przelacz na jasny motyw',
darkModeSwitchTitle: 'Przelacz na ciemny motyw',
docFooter: { prev: 'Poprzednia', next: 'Nastepna' },
},
},
},
}For development in this repository, use npm run ... scripts (they call the local CLI entrypoint).
When Greg is installed in a project, the greg command is still available via npm scripts and npx greg ....
| Command | Description |
|---|---|
greg init |
Interactive project scaffolding |
greg dev |
Start Vite dev server |
greg build |
Production build (auto versioning) |
greg build:static |
Production build + static export |
greg build:markdown |
Export resolved markdown |
greg preview |
Preview production build |
greg search-server |
Standalone search API server |
Greg supports two source strategies configured under greg.config.* > versioning:
branches(default): reads docs from configured git branches/refs and caches snapshots/builds per commit SHAfolders: reads docs directly from version folders in the working tree
- Put all versioning config in
greg.config.js(orgreg.config.ts) underversioning. - Choose one strategy in
versioning.strategy. - Map each built version id to its source:
- branch mode:
versioning.branches[]withversion+branch - folder mode:
versioning.folders[]withversion+dir
- branch mode:
- Set
versioning.defaultand optionalversioning.aliasesfor selector behavior.
Use this when each docs version should come from a Git branch/ref.
What to configure:
versioning.strategy = 'branches'versioning.branches[]entries withversion,branch, optionaldocsDir,titleversioning.defaultand optionalversioning.aliases
Example versioning value:
export default {
versioning: {
strategy: 'branches',
default: 'latest',
aliases: {
latest: '2.1',
stable: '2.0'
},
branches: [
{ version: '2.1', branch: 'main', title: '2.1' },
{ version: '2.0', branch: 'release/2.0', title: '2.0' }
]
}
}Use this when each docs version should come from a directory in the working tree.
What to configure:
versioning.strategy = 'folders'versioning.folders[]entries withversion,dir, optionalsrcDir,titleversioning.defaultand optionalversioning.aliases
Example versioning value:
export default {
versioning: {
strategy: 'folders',
default: 'latest',
aliases: {
latest: '2.1',
stable: '2.0'
},
folders: [
{ version: '2.1', dir: './docs', title: '2.1' },
{ version: '2.0', dir: './versions/2.0/docs', title: '2.0' }
]
}
}After configuration is in place, run:
greg buildOutput is generated to <outDir>/__versions/<version> (default dist/__versions/<version>) and a manifest is written to <outDir>/__versions/versions.json.
After that, Greg syncs the default version to dist/ so the root output is directly hostable.
Defaults are VitePress-compatible:
outDircomes from top-levelgreg.config.* > outDir(defaultdist)- manifest path prefix is based on top-level
greg.config.* > base(default/)
Optional UI labels/messages can be configured under versioning.ui:
export default {
versioning: {
ui: {
versionMenuLabel: 'Version',
manifestUnavailableText: 'Version selector unavailable',
showManifestUnavailableStatus: false,
outdatedVersionMessage: 'You are viewing an older version ({current}). Recommended: {default}.',
outdatedVersionActionLabel: 'Go to latest'
}
}
}To override those labels per locale, use versioning.locales:
In branches strategy, Greg stores build cache under .greg/version-cache/builds/... using a short commit SHA prefix.
- default prefix length:
7 - configurable in
greg.config.* > versioning.cacheShaLength - can be overridden per run via env
GREG_CACHE_SHA_LENGTH - allowed range:
7..40 - cache folder key format:
<shortSha>-<workspaceBuildFingerprint> - the suffix avoids stale cache reuse when local build inputs/config changed but branch commit SHA stayed the same
Example: if main still points to the same commit, but you changed vite.config.js or Markdown build plugins locally, Greg uses a different cache folder because the workspace fingerprint changes.
Example:
export default {
versioning: {
cacheShaLength: 12,
},
}GREG_CACHE_SHA_LENGTH=16 greg buildexport default {
versioning: {
locales: {
'/': {
ui: {
versionMenuLabel: 'Version'
}
},
'/pl/': {
ui: {
versionMenuLabel: 'Wersja'
}
}
}
}
}Resolution order for versioning UI text is:
versioning.locales[active-locale].uiversioning.ui- built-in default text
If versions.json cannot be loaded, Greg now shows a subtle fallback text in the header instead of the selector.
Example manifest:
{
"default": "latest",
"versions": [
{ "version": "2.1", "title": "2.1", "path": "/__versions/2.1/" },
{ "version": "2.0", "title": "2.0", "path": "/__versions/2.0/" }
],
"aliases": {
"latest": "2.1",
"stable": "2.0"
}
}Generate a fully expanded markdown snapshot (all <!--@include: ...--> and <<< ... resolved)
for AI knowledge-base ingestion or server-side indexing pipelines.
greg build:markdownOutput is written to dist/resolved-markdown and mirrors the docs/ structure.
Greg ships types at @dominikcz/greg. greg.config.ts is supported — it is transpiled via esbuild at build time.
import type { GregConfig } from '@dominikcz/greg'
export default {
srcDir: 'docs',
docsBase: '',
mainTitle: 'My Docs',
} satisfies GregConfigsrcDir can also be an array when your docs are split across multiple folders:
import type { GregConfig } from '@dominikcz/greg'
export default {
srcDir: ['docs', 'api-docs', 'handbook'],
docsBase: '',
} satisfies GregConfigWhen multiple folders contain the same relative path (for example guide/index.md),
the later entry in the srcDir array overrides the earlier one.
Note:
svelte.configmust remain a.jsfile —@sveltejs/vite-plugin-svelteloads it directly via Node ESM without a TypeScript transform.
- edit mode
- comments
- code cleanup