orama/website/vite.config.ts

96 lines
2.8 KiB
TypeScript

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";
import mdx from "@mdx-js/rollup";
import remarkGfm from "remark-gfm";
import rehypeSlug from "rehype-slug";
import fs from "node:fs";
import path from "node:path";
import type { Plugin } from "vite";
/**
* Vite plugin that generates a search index from MDX heading markers.
* Exposes a virtual module `virtual:docs-search-index` containing all
* h2 sections extracted from `src/docs/` MDX files at build time.
*/
function docsSearchIndexPlugin(): Plugin {
const virtualId = "virtual:docs-search-index";
const resolvedId = "\0" + virtualId;
return {
name: "docs-search-index",
resolveId(id) {
if (id === virtualId) return resolvedId;
},
load(id) {
if (id !== resolvedId) return;
const docsDir = path.resolve(__dirname, "src/docs");
const entries: {
pageTitle: string;
pageSlug: string;
sectionTitle: string;
sectionId: string;
persona: string;
}[] = [];
function walk(dir: string) {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
if (entry.isDirectory()) {
walk(path.join(dir, entry.name));
} else if (entry.name.endsWith(".mdx")) {
const fullPath = path.join(dir, entry.name);
const relative = path.relative(docsDir, fullPath);
const slug = relative.replace(/\.mdx$/, "");
const raw = fs.readFileSync(fullPath, "utf-8");
let persona = "developer";
if (slug.startsWith("operator/")) persona = "operator";
else if (slug.startsWith("contributor/")) persona = "contributor";
const titleMatch = raw.match(/^#\s+(.+)$/m);
const pageTitle = titleMatch?.[1] ?? slug;
const h2Regex = /^##\s+(.+)$/gm;
let match;
while ((match = h2Regex.exec(raw)) !== null) {
const sectionTitle = match[1];
const sectionId = sectionTitle
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/(^-|-$)/g, "");
entries.push({
pageTitle,
pageSlug: slug,
sectionTitle,
sectionId,
persona,
});
}
}
}
}
walk(docsDir);
return `export const SECTION_INDEX = ${JSON.stringify(entries)};`;
},
};
}
export default defineConfig({
plugins: [
docsSearchIndexPlugin(),
{
enforce: 'pre' as const,
...mdx({
providerImportSource: '@mdx-js/react',
remarkPlugins: [remarkGfm],
rehypePlugins: [rehypeSlug],
}),
},
react({ include: /\.(jsx|tsx|mdx)$/ }),
tailwindcss(),
],
});