Unified Cache System
Overview
The framework uses a unified cache manager that provides:
- Single cache system for content, sidebar, theme, settings, and config
- Selective invalidation based on file type (no unnecessary cache clears)
- HMR integration with automatic cache invalidation on file changes
- No hash computation overhead - trusts HMR for change detection
Performance
| Metric | First Request | Cached | Improvement |
|---|---|---|---|
| Page load | ~150-200ms | ~5ms | 97% faster |
| Sidebar build | ~10-15ms | ~1ms | 90% faster |
| Theme CSS | ~5-10ms | ~0.5ms | 95% faster |
| Settings load | ~2-3ms | ~0.1ms | 97% faster |
Architecture
┌─────────────────────────────────────────────────────────────────────────────┐
│ UNIFIED CACHE MANAGER │
│ src/loaders/cache-manager.ts │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Content │ │ Sidebar │ │ Theme │ │ Settings │ │
│ │ Cache │ │ Cache │ │ Cache │ │ Cache │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │ │
│ └────────────────┴────────────────┴────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ globalThis │ Persists across requests │
│ │ shared state │ in dev server │
│ └─────────────────┘ │
│ │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ SELECTIVE INVALIDATION (on HMR file change) │
│ │
│ File Type │ Caches Invalidated │
│ ─────────────────┼──────────────────────────────────── │
│ .md/.mdx │ content + sidebar │
│ settings.json │ sidebar + settings │
│ theme.yaml/.css │ theme + combined CSS │
│ site.yaml │ config + theme │
│ navbar/footer │ config only │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Cache Types
1. Content Cache
Caches parsed markdown content with headings.
// Key: ${dataPath}:${pattern}:${contentType}:${sort}:${order}
// Value: LoadedContent[]
interface LoadedContent {
slug: string;
content: string; // Rendered HTML
headings: Heading[]; // Extracted for TOC/outline
data: ContentData; // Frontmatter
filePath: string;
relativePath: string;
}
2. Sidebar Cache
Caches the sidebar tree structure.
// Key: ${dataPath}:${basePath}
// Value: SidebarNode[]
type SidebarNode = SidebarItem | SidebarSection;
3. Theme Cache
Caches theme configuration and combined CSS.
// Key: themeRef (e.g., "@theme/minimal")
// Value: ThemeConfig
interface ThemeConfig {
name: string;
path: string;
manifest: ThemeManifest;
css: string; // Individual theme CSS
isDefault: boolean;
}
// Combined CSS cache (with inheritance resolved)
// Stored separately for getThemeCSS() results
4. Settings Cache
Caches content directory settings.
// Key: absolutePath to settings.json directory
// Value: ContentSettings
interface ContentSettings {
sidebar: { collapsed, collapsible, sort, depth };
outline: { enabled, levels, title };
pagination: { enabled, showPrevNext };
}
HMR Integration
The dev toolbar integration watches all configured directories:
// src/dev-toolbar/integration.ts
// Paths read from .env
const watchPaths = {
data: DATA_DIR, // Content files
config: CONFIG_DIR, // site.yaml, navbar.yaml, footer.yaml
assets: ASSETS_DIR, // Images, logos
themes: THEMES_DIR, // Theme CSS and manifests
};
// Events handled
server.watcher.on('add', onFileAdd); // New files
server.watcher.on('unlink', onFileDelete); // Deleted files
handleHotUpdate({ file }); // Modified files
File Type Detection
function detectFileType(filePath: string): FileType {
const basename = path.basename(filePath);
if (basename === 'settings.json') return 'settings';
if (basename === 'site.yaml') return 'config';
if (basename === 'theme.yaml') return 'theme';
if (ext === '.md' || ext === '.mdx') return 'content';
if (ext === '.css' && inThemesDir) return 'theme';
return 'unknown';
}
Files Structure
src/
├── loaders/
│ ├── cache-manager.ts ← Unified cache with selective invalidation
│ ├── cache.ts ← Error/warning collection only
│ ├── data.ts ← Content loading (uses cache-manager)
│ └── theme.ts ← Theme loading (uses cache-manager)
│
├── hooks/
│ └── useSidebar.ts ← Sidebar building (uses cache-manager)
│
└── dev-toolbar/
└── integration.ts ← HMR watcher, calls cache invalidation
Usage
Cache is Automatic
No manual cache management needed. The system:
- Checks cache on every load
- Returns cached data if available
- Loads from disk on cache miss
- Stores in cache for next request
- Invalidates via HMR when files change
API
import cacheManager from '@loaders/cache-manager';
// Get cached data (returns null on miss)
const data = cacheManager.getCached<T>('content', key);
// Set cache entry
cacheManager.setCache('content', key, data, dependencies);
// Clear specific cache
cacheManager.clearCache('sidebar');
// Get statistics
const stats = cacheManager.getCacheStats();
// { caches: { content: { size, stats }, ... }, fileRegistry, watchPaths }
Error/Warning Collection
Errors and warnings are collected separately from content caching:
// src/loaders/cache.ts
import { addError, addWarning, getAllIssues } from '@loaders/cache';
// Collect errors during parsing
addError({
file: 'docs/example.md',
type: 'asset-missing',
message: 'File not found: ./assets/image.png',
suggestion: 'Create the file or update the path',
});
// Get all issues for dev toolbar
const { errors, warnings } = getAllIssues();
Error Types
| Type | Description |
|---|---|
asset-missing |
Referenced file not found |
frontmatter |
Invalid frontmatter syntax |
syntax |
Markdown parsing error |
config |
Configuration issue |
theme-not-found |
Theme directory missing |
theme-invalid-manifest |
Invalid theme.yaml |
Trade-offs
Pros
- 97% faster subsequent page loads
- Selective invalidation - only affected caches cleared
- No hash computation - trusts HMR, no MD5 overhead
- Unified architecture - single cache manager
- Theme CSS cached - includes inheritance resolution
Cons
- Increased memory usage (all caches in memory)
- First request still cold (must load from disk)
- Requires dev server restart if cache corrupts (rare)