Skip to content

Commit fe71a63

Browse files
committed
adding index now + benchmark pages
1 parent 31efcbb commit fe71a63

File tree

4 files changed

+181
-163
lines changed

4 files changed

+181
-163
lines changed

website/app/benchmarks/page.tsx

Lines changed: 1 addition & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ import { Metadata } from "next";
22
import { Card, CardContent } from "@/components/ui/card";
33
import { Button } from "@/components/ui/button";
44
import Link from "next/link";
5-
import { readFileSync, readdirSync, statSync, existsSync } from 'fs';
6-
import { join, extname } from 'path';
7-
import matter from 'gray-matter';
5+
import { getAllBenchmarks } from "@/lib/benchmarks";
86

97
export const metadata: Metadata = {
108
title: "RunMat Benchmarks - Performance Comparisons",
@@ -16,164 +14,6 @@ export const metadata: Metadata = {
1614
},
1715
};
1816

19-
interface Benchmark {
20-
slug: string;
21-
title: string;
22-
description: string;
23-
summary: string;
24-
imageUrl?: string;
25-
date: string;
26-
readTime: string;
27-
author: string;
28-
tags: string[];
29-
}
30-
31-
function extractTitleFromMarkdown(content: string): string {
32-
const lines = content.split('\n');
33-
for (const line of lines) {
34-
const trimmed = line.trim();
35-
if (trimmed.startsWith('# ')) {
36-
return trimmed.substring(2).trim();
37-
}
38-
}
39-
return 'Untitled Benchmark';
40-
}
41-
42-
function extractFirstParagraph(content: string): string {
43-
const lines = content.split('\n');
44-
let inParagraph = false;
45-
const paragraphLines: string[] = [];
46-
47-
for (const line of lines) {
48-
const trimmed = line.trim();
49-
if (trimmed.startsWith('#')) {
50-
if (inParagraph) break;
51-
continue;
52-
}
53-
if (!trimmed && !inParagraph) continue;
54-
if (trimmed) {
55-
inParagraph = true;
56-
paragraphLines.push(trimmed);
57-
} else if (inParagraph) {
58-
break;
59-
}
60-
}
61-
62-
const paragraph = paragraphLines.join(' ');
63-
return paragraph || 'Performance benchmark comparing RunMat against alternatives.';
64-
}
65-
66-
function truncateText(text: string, limit: number = 200): string {
67-
if (text.length <= limit) {
68-
return text;
69-
}
70-
return text.substring(0, limit).trimEnd() + '...';
71-
}
72-
73-
function extractFirstImageUrl(content: string): string | undefined {
74-
const imageRegex = /!\[[^\]]*\]\(([^)\s]+)(?:\s+"[^"]*")?\)/;
75-
const match = imageRegex.exec(content);
76-
return match ? match[1] : undefined;
77-
}
78-
79-
function getMimeTypeFromExtension(extension: string): string | undefined {
80-
switch (extension.toLowerCase()) {
81-
case '.png':
82-
return 'image/png';
83-
case '.jpg':
84-
case '.jpeg':
85-
return 'image/jpeg';
86-
case '.svg':
87-
return 'image/svg+xml';
88-
case '.webp':
89-
return 'image/webp';
90-
default:
91-
return undefined;
92-
}
93-
}
94-
95-
function getAllBenchmarks(): Benchmark[] {
96-
try {
97-
const benchmarksDir = join(process.cwd(), '..', 'benchmarks');
98-
const entries = readdirSync(benchmarksDir, { withFileTypes: true });
99-
100-
const benchmarks = entries
101-
.filter(entry => entry.isDirectory() && entry.name !== '.harness' && entry.name !== 'wgpu_profile')
102-
.map((entry): Benchmark | null => {
103-
const slug = entry.name;
104-
const readmePath = join(benchmarksDir, slug, 'README.md');
105-
106-
try {
107-
const fileContent = readFileSync(readmePath, 'utf-8');
108-
const { data: frontmatter, content } = matter(fileContent);
109-
110-
// Extract title from frontmatter or first heading
111-
const title = frontmatter.title || extractTitleFromMarkdown(content);
112-
113-
// Extract description from frontmatter or first paragraph
114-
const rawDescription = frontmatter.description || frontmatter.excerpt || extractFirstParagraph(content);
115-
const description = rawDescription || 'Performance benchmark comparing RunMat against alternatives.';
116-
const summary = truncateText(description);
117-
118-
const frontmatterImage = typeof frontmatter.image === 'string' ? frontmatter.image : undefined;
119-
const markdownImage = extractFirstImageUrl(content);
120-
const resolvedImagePath = frontmatterImage || markdownImage;
121-
122-
let imageUrl: string | undefined;
123-
if (resolvedImagePath) {
124-
if (resolvedImagePath.startsWith('http://') || resolvedImagePath.startsWith('https://')) {
125-
imageUrl = resolvedImagePath;
126-
} else {
127-
const sanitizedPath = resolvedImagePath.replace(/^\.?\//, '');
128-
const absolutePath = join(benchmarksDir, slug, sanitizedPath);
129-
if (existsSync(absolutePath)) {
130-
const mimeType = getMimeTypeFromExtension(extname(absolutePath));
131-
if (mimeType) {
132-
const fileBuffer = readFileSync(absolutePath);
133-
const base64 = fileBuffer.toString('base64');
134-
imageUrl = `data:${mimeType};base64,${base64}`;
135-
}
136-
}
137-
}
138-
}
139-
140-
// Get file modification date as fallback
141-
const stats = statSync(readmePath);
142-
const defaultDate = stats.mtime.toISOString();
143-
144-
return {
145-
slug,
146-
title,
147-
description,
148-
summary,
149-
imageUrl,
150-
date: frontmatter.date || defaultDate,
151-
readTime: frontmatter.readTime || '5 min read',
152-
author: frontmatter.author || 'RunMat Team',
153-
tags: frontmatter.tags || []
154-
};
155-
} catch (error) {
156-
console.error(`Error reading benchmark ${slug}:`, error);
157-
return null;
158-
}
159-
})
160-
.filter((benchmark): benchmark is Benchmark => benchmark !== null);
161-
162-
// Sort by date (newest first) or alphabetically if no date
163-
return benchmarks.sort((a, b) => {
164-
const dateA = new Date(a.date).getTime();
165-
const dateB = new Date(b.date).getTime();
166-
if (dateA !== dateB) {
167-
return dateB - dateA;
168-
}
169-
return a.title.localeCompare(b.title);
170-
});
171-
} catch (error) {
172-
console.error('Error reading benchmarks:', error);
173-
return [];
174-
}
175-
}
176-
17717
export default function BenchmarksPage() {
17818
const benchmarks = getAllBenchmarks();
17919

@@ -270,4 +110,3 @@ export default function BenchmarksPage() {
270110
</div>
271111
);
272112
}
273-

website/app/sitemap.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { MetadataRoute } from 'next'
22
import { getAllBlogPosts } from '@/lib/blog'
3+
import { getAllBenchmarks } from '@/lib/benchmarks'
34
import { loadBuiltins } from '@/lib/builtins'
45
import { flatten } from '@/content/docs'
56

@@ -34,6 +35,12 @@ export default function sitemap(): MetadataRoute.Sitemap {
3435
changeFrequency: 'daily',
3536
priority: 0.5,
3637
},
38+
{
39+
url: `${baseUrl}/benchmarks`,
40+
lastModified: currentDate,
41+
changeFrequency: 'daily',
42+
priority: 0.5,
43+
},
3744
{
3845
url: `${baseUrl}/license`,
3946
lastModified: currentDate,
@@ -73,6 +80,17 @@ export default function sitemap(): MetadataRoute.Sitemap {
7380
priority: 0.4,
7481
}))
7582

83+
const benchmarkRoutes: MetadataRoute.Sitemap = getAllBenchmarks().map(benchmark => {
84+
const parsedDate = benchmark.date ? new Date(benchmark.date) : null
85+
const lastModified = parsedDate && !Number.isNaN(parsedDate.getTime()) ? parsedDate : currentDate
86+
return {
87+
url: `${baseUrl}/benchmarks/${benchmark.slug}`,
88+
lastModified,
89+
changeFrequency: 'monthly',
90+
priority: 0.5,
91+
}
92+
})
93+
7694
const builtinRoutes: MetadataRoute.Sitemap = loadBuiltins().map(builtin => ({
7795
url: `${baseUrl}/docs/reference/builtins/${builtin.slug}`,
7896
lastModified: currentDate,
@@ -82,7 +100,7 @@ export default function sitemap(): MetadataRoute.Sitemap {
82100

83101
const seen = new Set<string>()
84102
const merged: MetadataRoute.Sitemap = []
85-
for (const route of [...staticRoutes, ...docRoutes, ...blogPostRoutes, ...builtinRoutes]) {
103+
for (const route of [...staticRoutes, ...blogPostRoutes, ...benchmarkRoutes, ...builtinRoutes, ...docRoutes]) {
86104
if (seen.has(route.url)) continue
87105
seen.add(route.url)
88106
merged.push(route)

website/lib/benchmarks.ts

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import { readFileSync, readdirSync, statSync, existsSync } from 'fs'
2+
import { extname, join } from 'path'
3+
import matter from 'gray-matter'
4+
5+
export interface BenchmarkSummary {
6+
slug: string
7+
title: string
8+
description: string
9+
summary: string
10+
imageUrl?: string
11+
date: string
12+
readTime: string
13+
author: string
14+
tags: string[]
15+
}
16+
17+
function extractTitleFromMarkdown(content: string): string {
18+
const lines = content.split('\n')
19+
for (const line of lines) {
20+
const trimmed = line.trim()
21+
if (trimmed.startsWith('# ')) {
22+
return trimmed.substring(2).trim()
23+
}
24+
}
25+
return 'Untitled Benchmark'
26+
}
27+
28+
function extractFirstParagraph(content: string): string {
29+
const lines = content.split('\n')
30+
let inParagraph = false
31+
const paragraphLines: string[] = []
32+
33+
for (const line of lines) {
34+
const trimmed = line.trim()
35+
if (trimmed.startsWith('#')) {
36+
if (inParagraph) break
37+
continue
38+
}
39+
if (!trimmed && !inParagraph) continue
40+
if (trimmed) {
41+
inParagraph = true
42+
paragraphLines.push(trimmed)
43+
} else if (inParagraph) {
44+
break
45+
}
46+
}
47+
48+
const paragraph = paragraphLines.join(' ')
49+
return paragraph || 'Performance benchmark comparing RunMat against alternatives.'
50+
}
51+
52+
function truncateText(text: string, limit = 200): string {
53+
if (text.length <= limit) {
54+
return text
55+
}
56+
return text.substring(0, limit).trimEnd() + '...'
57+
}
58+
59+
function extractFirstImageUrl(content: string): string | undefined {
60+
const imageRegex = /!\[[^\]]*\]\(([^)\s]+)(?:\s+"[^"]*")?\)/
61+
const match = imageRegex.exec(content)
62+
return match ? match[1] : undefined
63+
}
64+
65+
function getMimeTypeFromExtension(extension: string): string | undefined {
66+
switch (extension.toLowerCase()) {
67+
case '.png':
68+
return 'image/png'
69+
case '.jpg':
70+
case '.jpeg':
71+
return 'image/jpeg'
72+
case '.svg':
73+
return 'image/svg+xml'
74+
case '.webp':
75+
return 'image/webp'
76+
default:
77+
return undefined
78+
}
79+
}
80+
81+
export function getAllBenchmarks(): BenchmarkSummary[] {
82+
try {
83+
const benchmarksDir = join(process.cwd(), '..', 'benchmarks')
84+
const entries = readdirSync(benchmarksDir, { withFileTypes: true })
85+
86+
const benchmarks = entries
87+
.filter(entry => entry.isDirectory() && entry.name !== '.harness' && entry.name !== 'wgpu_profile')
88+
.map((entry): BenchmarkSummary | null => {
89+
const slug = entry.name
90+
const readmePath = join(benchmarksDir, slug, 'README.md')
91+
92+
try {
93+
const fileContent = readFileSync(readmePath, 'utf-8')
94+
const { data: frontmatter, content } = matter(fileContent)
95+
96+
const title = frontmatter.title || extractTitleFromMarkdown(content)
97+
const rawDescription = frontmatter.description || frontmatter.excerpt || extractFirstParagraph(content)
98+
const description = rawDescription || 'Performance benchmark comparing RunMat against alternatives.'
99+
const summary = truncateText(description)
100+
101+
const frontmatterImage = typeof frontmatter.image === 'string' ? frontmatter.image : undefined
102+
const markdownImage = extractFirstImageUrl(content)
103+
const resolvedImagePath = frontmatterImage || markdownImage
104+
105+
let imageUrl: string | undefined
106+
if (resolvedImagePath) {
107+
if (resolvedImagePath.startsWith('http://') || resolvedImagePath.startsWith('https://')) {
108+
imageUrl = resolvedImagePath
109+
} else {
110+
const sanitizedPath = resolvedImagePath.replace(/^\.?\//, '')
111+
const absolutePath = join(benchmarksDir, slug, sanitizedPath)
112+
if (existsSync(absolutePath)) {
113+
const mimeType = getMimeTypeFromExtension(extname(absolutePath))
114+
if (mimeType) {
115+
const fileBuffer = readFileSync(absolutePath)
116+
const base64 = fileBuffer.toString('base64')
117+
imageUrl = `data:${mimeType};base64,${base64}`
118+
}
119+
}
120+
}
121+
}
122+
123+
const stats = statSync(readmePath)
124+
const defaultDate = stats.mtime.toISOString()
125+
126+
return {
127+
slug,
128+
title,
129+
description,
130+
summary,
131+
imageUrl,
132+
date: frontmatter.date || defaultDate,
133+
readTime: frontmatter.readTime || '5 min read',
134+
author: frontmatter.author || 'RunMat Team',
135+
tags: frontmatter.tags || [],
136+
}
137+
} catch (error) {
138+
console.error(`Error reading benchmark ${slug}:`, error)
139+
return null
140+
}
141+
})
142+
.filter((benchmark): benchmark is BenchmarkSummary => benchmark !== null)
143+
144+
return benchmarks.sort((a, b) => {
145+
const dateA = new Date(a.date).getTime()
146+
const dateB = new Date(b.date).getTime()
147+
if (dateA !== dateB) {
148+
return dateB - dateA
149+
}
150+
return a.title.localeCompare(b.title)
151+
})
152+
} catch (error) {
153+
console.error('Error reading benchmarks:', error)
154+
return []
155+
}
156+
}
157+
158+
export function getBenchmarkSlugs(): string[] {
159+
return getAllBenchmarks().map(benchmark => benchmark.slug)
160+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
aadb228130074e939247c74f7f4160d8

0 commit comments

Comments
 (0)