Vite & Vue powered static site generator with Vue-based theming and markdown processing
—
VitePress provides an enhanced markdown processing system built on MarkdownIt with Vue component support, syntax highlighting, custom containers, and extensive plugin ecosystem. The markdown processor supports frontmatter, custom renderers, and seamless integration with Vue components.
Core functions for creating and configuring markdown renderers with VitePress enhancements.
Creates a fully configured MarkdownIt instance with VitePress plugins and enhancements.
/**
* Creates markdown renderer instance with VitePress plugins
* @param options - Markdown processing configuration
* @param base - Base URL for resolving relative links
* @param logger - Logger instance for debugging
* @returns Configured MarkdownIt instance with VitePress plugins
*/
function createMarkdownRenderer(
options?: MarkdownOptions,
base?: string,
logger?: Logger
): MarkdownIt;
interface MarkdownOptions {
/**
* Show line numbers in code blocks
* @default false
*/
lineNumbers?: boolean;
/**
* Custom MarkdownIt configuration function
*/
config?: (md: MarkdownIt) => void;
/**
* Pre-configuration hook (runs before VitePress plugins)
*/
preConfig?: (md: MarkdownIt) => void;
/**
* Enable/disable markdown caching
* @default true
*/
cache?: boolean;
/**
* Syntax highlighting theme configuration
*/
theme?: ThemeOptions | { light: ThemeOptions; dark: ThemeOptions };
/**
* Supported programming languages for syntax highlighting
*/
languages?: LanguageInput[];
/**
* Custom transformers for syntax highlighting
*/
transformers?: ShikiTransformer[];
/**
* Default language for code blocks without specified language
*/
defaultHighlightLang?: string;
/**
* Code groups configuration
*/
codeTransformers?: CodeTransformer[];
/**
* Anchor links configuration
*/
anchor?: AnchorOptions;
/**
* Table of contents generation options
*/
toc?: TocOptions;
/**
* External links attributes and processing
*/
externalLinks?: Record<string, string>;
/**
* Math rendering configuration
*/
math?: boolean | MathOptions;
/**
* Image processing options
*/
image?: ImageOptions;
/**
* Custom container configuration
*/
container?: ContainerOptions;
/**
* Markdown parser options (passed to MarkdownIt)
*/
breaks?: boolean;
linkify?: boolean;
typographer?: boolean;
quotes?: string | string[];
}Usage Examples:
import { createMarkdownRenderer } from "vitepress";
// Basic markdown renderer
const md = createMarkdownRenderer();
const html = md.render("# Hello World\n\nThis is **bold** text.");
// Custom renderer with syntax highlighting
const md = createMarkdownRenderer({
lineNumbers: true,
theme: {
light: "github-light",
dark: "github-dark"
},
languages: ["javascript", "typescript", "vue", "bash"],
defaultHighlightLang: "text"
});
// Advanced configuration with custom plugins
const md = createMarkdownRenderer({
config: (md) => {
// Add custom MarkdownIt plugins
md.use(require("markdown-it-footnote"));
md.use(require("markdown-it-deflist"));
// Custom renderer rules
md.renderer.rules.table_open = () => '<div class="table-container"><table>';
md.renderer.rules.table_close = () => '</table></div>';
},
preConfig: (md) => {
// Pre-configuration (runs before VitePress plugins)
md.set({ breaks: true, linkify: true });
},
externalLinks: {
target: "_blank",
rel: "noopener noreferrer"
}
});
// Math and advanced features
const md = createMarkdownRenderer({
math: true,
anchor: {
permalink: true,
permalinkBefore: true,
permalinkSymbol: "#"
},
container: {
tipLabel: "TIP",
warningLabel: "WARNING",
dangerLabel: "DANGER",
infoLabel: "INFO"
}
});Detailed configuration options for markdown processing features.
interface ThemeOptions {
/**
* Shiki theme name or theme object
*/
name?: string;
/**
* Custom theme definition
*/
theme?: Theme;
}
type LanguageInput =
| string
| {
id: string;
scopeName: string;
grammar: Grammar;
aliases?: string[];
};
interface CodeTransformer {
/**
* Transform code blocks
*/
name: string;
preprocess?: (code: string, options: any) => string;
postprocess?: (html: string, options: any) => string;
}
interface ShikiTransformer {
name: string;
preprocess?: (code: string, options: TransformerOptions) => string;
postprocess?: (html: string, options: TransformerOptions) => string;
tokens?: (tokens: ThemedToken[][], options: TransformerOptions) => void;
}interface AnchorOptions {
/**
* Minimum header level to generate anchors for
* @default 2
*/
level?: [number, number];
/**
* Generate permalink anchors
* @default true
*/
permalink?: boolean;
/**
* Permalink symbol
* @default '#'
*/
permalinkSymbol?: string;
/**
* Place permalink before header text
* @default false
*/
permalinkBefore?: boolean;
/**
* Custom permalink render function
*/
permalinkHref?: (slug: string) => string;
/**
* Custom slug generation function
*/
slugify?: (str: string) => string;
/**
* Additional CSS classes for anchor links
*/
permalinkClass?: string;
/**
* ARIA label for anchor links
*/
permalinkAriaLabel?: string;
}
interface TocOptions {
/**
* Header levels to include in TOC
* @default [2, 3]
*/
level?: [number, number];
/**
* Custom slug function for TOC links
*/
slugify?: (str: string) => string;
/**
* Include anchor links in TOC
* @default true
*/
includeLevel?: number[];
/**
* Custom TOC marker token
*/
markerPattern?: RegExp;
}interface ContainerOptions {
/**
* Custom container labels
*/
tipLabel?: string;
warningLabel?: string;
dangerLabel?: string;
infoLabel?: string;
detailsLabel?: string;
/**
* Custom container types
*/
customTypes?: Record<string, ContainerType>;
}
interface ContainerType {
/**
* Container label/title
*/
label?: string;
/**
* Custom render function
*/
render?: (tokens: Token[], idx: number, options: any, env: any) => string;
/**
* Container CSS class
*/
className?: string;
}
interface MathOptions {
/**
* Math rendering engine
* @default 'mathjax'
*/
engine?: "mathjax" | "katex";
/**
* Math delimiters configuration
*/
delimiters?: {
inline?: [string, string];
block?: [string, string];
};
/**
* Engine-specific options
*/
options?: Record<string, any>;
}
interface ImageOptions {
/**
* Enable lazy loading for images
* @default false
*/
lazy?: boolean;
/**
* Generate responsive image sets
* @default false
*/
responsive?: boolean;
/**
* Image optimization options
*/
optimization?: {
/**
* Enable WebP conversion
*/
webp?: boolean;
/**
* Quality settings
*/
quality?: number;
/**
* Resize breakpoints
*/
breakpoints?: number[];
};
}Environment and context objects used during markdown processing.
Environment object passed through the markdown rendering pipeline.
/**
* Markdown rendering environment containing metadata and context
*/
interface MarkdownEnv {
/**
* Raw markdown content without frontmatter
*/
content?: string;
/**
* Extracted excerpt (rendered or raw based on configuration)
*/
excerpt?: string;
/**
* Parsed frontmatter data
*/
frontmatter?: Record<string, unknown>;
/**
* Extracted headers from content
*/
headers?: Header[];
/**
* Vue SFC blocks extracted from markdown
*/
sfcBlocks?: MarkdownSfcBlocks;
/**
* Extracted page title
*/
title?: string;
/**
* Current file path being processed
*/
path: string;
/**
* Relative path from source root
*/
relativePath: string;
/**
* Whether clean URLs are enabled
*/
cleanUrls: boolean;
/**
* Links found in the content
*/
links?: string[];
/**
* Included file references
*/
includes?: string[];
/**
* Real file system path (may differ from path for virtual files)
*/
realPath?: string;
/**
* Current locale index for multi-language sites
*/
localeIndex?: string;
}Vue Single File Component blocks extracted from markdown.
interface MarkdownSfcBlocks {
/**
* Main template block
*/
template: SfcBlock | null;
/**
* Main script block
*/
script: SfcBlock | null;
/**
* Script setup block
*/
scriptSetup: SfcBlock | null;
/**
* All script blocks (including custom types)
*/
scripts: SfcBlock[];
/**
* All style blocks
*/
styles: SfcBlock[];
/**
* Custom blocks (e.g., i18n, docs)
*/
customBlocks: SfcBlock[];
}
interface SfcBlock {
/**
* Block type (script, style, template, etc.)
*/
type: string;
/**
* Full block content including tags
*/
content: string;
/**
* Content with opening and closing tags stripped
*/
contentStripped: string;
/**
* Opening tag
*/
tagOpen: string;
/**
* Closing tag
*/
tagClose: string;
}Advanced content loading and processing capabilities.
Create content loaders for processing multiple markdown files with shared processing logic.
/**
* Creates a content loader for markdown files
* @param pattern - Glob patterns for files to load
* @param options - Loader configuration options
* @returns Object with watch and load properties for content loading
*/
function createContentLoader<T = ContentData[]>(
pattern: string | string[],
options?: ContentOptions<T>
): ContentLoader<T>;
interface ContentOptions<T> {
/**
* Include raw source content
* @default false
*/
includeSrc?: boolean;
/**
* Render markdown to HTML
* @default false
*/
render?: boolean;
/**
* Extract excerpt from content
*/
excerpt?: boolean | string | ((file: ContentData, options: ContentOptions<T>) => string);
/**
* Transform loaded data
*/
transform?: (data: ContentData[], options: ContentOptions<T>) => T | Promise<T>;
/**
* Glob options for file matching
*/
globOptions?: GlobOptions;
}
interface ContentData {
/**
* Content URL/path
*/
url: string;
/**
* Raw markdown source (if includeSrc: true)
*/
src?: string;
/**
* Rendered HTML (if render: true)
*/
html?: string;
/**
* Frontmatter data
*/
frontmatter: Record<string, any>;
/**
* Extracted excerpt (if excerpt option enabled)
*/
excerpt?: string;
}
interface ContentLoader<T> {
/**
* Files to watch for changes
*/
watch: string[];
/**
* Load and process content
*/
load(): Promise<T>;
}Usage Examples:
// Basic content loading
const loader = createContentLoader("posts/*.md", {
includeSrc: true,
render: true,
excerpt: true
});
const posts = await loader.load();
// Advanced content processing with transformation
const blogLoader = createContentLoader("blog/**/*.md", {
render: true,
excerpt: "<!-- more -->",
transform: (data) => {
return data
.filter(post => post.frontmatter.published !== false)
.sort((a, b) => +new Date(b.frontmatter.date) - +new Date(a.frontmatter.date))
.map(post => ({
...post,
readingTime: calculateReadingTime(post.src)
}));
}
});
// Use in data files (.data.ts)
export default {
watch: ["./posts/**/*.md"],
load: () => blogLoader.load()
};Type helper for defining data loaders with proper TypeScript support.
/**
* Type helper for defining data loaders
* @param loader - LoaderModule object with watch and load properties
* @returns Same loader object for type inference
*/
function defineLoader<T = any>(loader: LoaderModule<T>): LoaderModule<T>;
interface LoaderModule<T = any> {
/**
* Files or patterns to watch for changes
*/
watch?: string[] | string;
/**
* Load function that returns data
* @param watchedFiles - Array of watched file paths that changed
* @returns Data to be used in pages
*/
load: (watchedFiles: string[]) => T | Promise<T>;
}Usage Examples:
// blog-posts.data.ts
import { defineLoader } from "vitepress";
import { createContentLoader } from "vitepress";
export default defineLoader({
watch: ["./blog/**/*.md"],
load: async (watchedFiles) => {
const loader = createContentLoader("blog/**/*.md", {
render: true,
excerpt: true,
transform: (data) => data
.filter(post => post.frontmatter.published)
.sort((a, b) => +new Date(b.frontmatter.date) - +new Date(a.frontmatter.date))
});
return await loader.load();
}
});
// Use loaded data in pages
<script setup>
import { data as posts } from "./blog-posts.data";
// posts is typed and contains processed blog data
console.log("Latest posts:", posts.slice(0, 5));
</script>Creating and configuring custom markdown plugins for extended functionality.
/**
* Custom MarkdownIt plugin function signature
*/
type MarkdownItPlugin = (
md: MarkdownIt,
options?: any
) => void;
/**
* VitePress markdown plugin with additional context
*/
interface VitePressPlugin {
/**
* Plugin name for debugging
*/
name: string;
/**
* Plugin configuration function
*/
configureParser?: (md: MarkdownIt, options: MarkdownOptions) => void;
/**
* Plugin render function
*/
configureRenderer?: (md: MarkdownIt, env: MarkdownEnv) => void;
/**
* Plugin cleanup function
*/
cleanup?: () => void;
}Usage Examples:
// Custom plugin for special containers
const customContainerPlugin: MarkdownItPlugin = (md, options) => {
const containerPlugin = require("markdown-it-container");
// Add custom "demo" container
md.use(containerPlugin, "demo", {
render: (tokens, idx, _options, env) => {
const token = tokens[idx];
const info = token.info.trim().slice(4).trim(); // Remove "demo"
if (token.nesting === 1) {
// Opening tag
return `<div class="demo-container">
<div class="demo-title">${info || "Demo"}</div>
<div class="demo-content">`;
} else {
// Closing tag
return `</div></div>`;
}
}
});
};
// Use in VitePress config
export default defineConfig({
markdown: {
config: (md) => {
md.use(customContainerPlugin);
// Add custom renderer for code blocks
const fence = md.renderer.rules.fence!;
md.renderer.rules.fence = (...args) => {
const [tokens, idx] = args;
const token = tokens[idx];
const lang = token.info.trim();
// Add copy button to code blocks
const result = fence(...args);
return result.replace(
/<\/div>$/,
`<button class="copy-code">Copy</button></div>`
);
};
}
}
});Install with Tessl CLI
npx tessl i tessl/npm-vitepress