import { readFileSync, readdirSync, existsSync } from 'fs' import { join, resolve, extname, basename } from 'path' import matter from 'gray-matter' import { marked } from 'marked' import * as yaml from 'js-yaml' const CONTENT_DIR = resolve(process.cwd(), 'content') const VIRTUAL_MODULE_ID = 'virtual:content' const RESOLVED_VIRTUAL_MODULE_ID = '\0' + VIRTUAL_MODULE_ID function readContentDir(subdir) { const dir = join(CONTENT_DIR, subdir) if (!existsSync(dir)) return [] return readdirSync(dir) .filter(f => !f.startsWith('.')) .map(filename => { const filepath = join(dir, filename) const ext = extname(filename) const slug = basename(filename, ext) if (ext === '.md') { const raw = readFileSync(filepath, 'utf-8') const { data, content } = matter(raw) return { ...data, slug, body: renderMarkdownContent(content), _source: `${subdir}/${filename}` } } if (ext === '.yaml' || ext === '.yml') { const raw = readFileSync(filepath, 'utf-8') const data = yaml.load(raw) return { ...data, slug, _source: `${subdir}/${filename}` } } return null }) .filter(Boolean) } export function renderMarkdownContent(content) { const tokens = marked.lexer(content) const firstContentToken = tokens.findIndex(token => token.type !== 'space') const firstToken = tokens[firstContentToken] if (firstToken?.type === 'heading' && firstToken.depth === 1) { tokens.splice(firstContentToken, 1) } return marked.parser(tokens) } function readMetaFile(filename) { const filepath = join(CONTENT_DIR, 'meta', filename) if (!existsSync(filepath)) return null const raw = readFileSync(filepath, 'utf-8') return yaml.load(raw) } function loadAllContent() { return { posts: readContentDir('posts'), kniepunkt: readContentDir('kniepunkt'), podcast: readContentDir('podcast'), talks: readContentDir('talks'), consulting: readContentDir('consulting'), resources: readContentDir('resources'), events: readContentDir('events'), meta: { profile: readMetaFile('profile.yaml'), stats: readMetaFile('stats.yaml'), testimonials: readMetaFile('testimonials.yaml'), logos: readMetaFile('logos.yaml'), services: readMetaFile('services.yaml'), about: readMetaFile('about.yaml'), speaking: readMetaFile('speaking.yaml'), newsletter: readMetaFile('newsletter.yaml'), } } } export default function contentPlugin() { return { name: 'vite-plugin-content', resolveId(id) { if (id === VIRTUAL_MODULE_ID) return RESOLVED_VIRTUAL_MODULE_ID }, load(id) { if (id === RESOLVED_VIRTUAL_MODULE_ID) { const content = loadAllContent() return `export default ${JSON.stringify(content)}` } }, handleHotUpdate({ file, server }) { if (file.includes('content')) { const mod = server.moduleGraph.getModuleById(RESOLVED_VIRTUAL_MODULE_ID) if (mod) { server.moduleGraph.invalidateModule(mod) return [mod] } } } } }