Skip to content

Commit 5294478

Browse files
21Chaniclaude
andcommitted
feat: serve raw markdown via .md URLs for LLM consumption
Add a Vite plugin that makes raw .mdx source available at .md URLs (e.g. /concepts/signals.md). In dev, files are served via middleware and copied to public/. At build time, files are copied to public/ so they ship as static assets. Also updates llms.txt to point to .md URLs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 3bcdb38 commit 5294478

File tree

3 files changed

+258
-210
lines changed

3 files changed

+258
-210
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,6 @@ netlify
4848

4949
public/sitemap.xml
5050
public/i18n-status
51+
52+
# Generated raw markdown files (from serveRawMarkdown vite plugin)
53+
public/**/*.md

app.config.ts

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export default defineConfig(
5858
},
5959
},
6060
vite: {
61-
plugins: [docsData(), heroCodeSnippet()],
61+
plugins: [docsData(), heroCodeSnippet(), serveRawMarkdown()],
6262
},
6363
},
6464
{
@@ -145,8 +145,53 @@ export default defineConfig(
145145
);
146146

147147
import { readFile } from "node:fs/promises";
148+
import { readFileSync, writeFileSync, mkdirSync, readdirSync } from "node:fs";
149+
import { join, relative, dirname, resolve } from "node:path";
148150
import { codeToHtml } from "shiki";
149151

152+
function serveRawMarkdown() {
153+
const srcDir = resolve("src/routes");
154+
const publicDir = resolve("public");
155+
156+
function findMdxFiles(dir: string): string[] {
157+
const results: string[] = [];
158+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
159+
const fullPath = join(dir, entry.name);
160+
if (entry.isDirectory()) {
161+
results.push(...findMdxFiles(fullPath));
162+
} else if (entry.name.endsWith(".mdx")) {
163+
results.push(fullPath);
164+
}
165+
}
166+
return results;
167+
}
168+
169+
return {
170+
name: "serve-raw-markdown",
171+
configureServer(server: any) {
172+
server.middlewares.use((req: any, res: any, next: any) => {
173+
if (!req.url?.endsWith(".md")) return next();
174+
const mdxPath = join(srcDir, req.url.replace(/\.md$/, ".mdx"));
175+
try {
176+
const content = readFileSync(mdxPath, "utf-8");
177+
res.setHeader("Content-Type", "text/plain; charset=utf-8");
178+
res.end(content);
179+
} catch {
180+
next();
181+
}
182+
});
183+
},
184+
buildStart() {
185+
for (const file of findMdxFiles(srcDir)) {
186+
const rel = relative(srcDir, file).replace(/\.mdx$/, ".md");
187+
const dest = join(publicDir, rel);
188+
mkdirSync(dirname(dest), { recursive: true });
189+
writeFileSync(dest, readFileSync(file, "utf-8"));
190+
}
191+
},
192+
};
193+
}
194+
150195
function heroCodeSnippet() {
151196
const virtualModuleId = "solid:hero-code-snippet";
152197
const resolveVirtualModuleId = "\0" + virtualModuleId;

0 commit comments

Comments
 (0)