feat: get latest version spacedf docs#33
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Code Review
This pull request replaces hardcoded version strings with dynamic versioning by fetching the latest release information from blog post metadata. It introduces a getLatestVersion utility to parse MDX frontmatter and updates the VersionLabel component and root layout to use this data. Feedback suggests handling cases where version data is missing in VersionLabel to prevent rendering errors and refactoring the version utility to use asynchronous file system operations to improve performance and prevent blocking the event loop.
| export default function VersionLabel({ latestVersion }) { | ||
| const handleClick = () => { | ||
| window.location.href = "/blog/v2026.02.13" | ||
| window.location.href = `/blog/${latestVersion?.version}` | ||
| } |
There was a problem hiding this comment.
The component should return null if latestVersion or its version property is missing. This prevents rendering an empty styled label and avoids navigating to an invalid URL (e.g., /blog/undefined).
export default function VersionLabel({ latestVersion }) {
if (!latestVersion?.version) return null
const handleClick = () => {
window.location.href = "/blog/" + latestVersion.version
}| import fs from "fs" | ||
| import path from "path" | ||
| import matter from "gray-matter" | ||
|
|
||
| type LatestVersion = { | ||
| slug: string | ||
| version: string | ||
| date?: string | ||
| title?: string | ||
| type?: string | ||
| author?: string | ||
| description?: string | ||
| } | ||
|
|
||
| export const getLatestVersion = async (): Promise<LatestVersion | null> => { | ||
| const POSTS_DIR = path.join(process.cwd(), "src/app/blog/(post)") | ||
|
|
||
| if (!fs.existsSync(POSTS_DIR)) return null | ||
|
|
||
| const results: LatestVersion[] = [] | ||
| const folders = fs.readdirSync(POSTS_DIR) | ||
|
|
||
| for (const folder of folders) { | ||
| const fullPath = path.join(POSTS_DIR, folder, "page.mdx") | ||
| if (!fs.existsSync(fullPath)) continue | ||
|
|
||
| const raw = fs.readFileSync(fullPath, "utf-8") | ||
| if (!raw) continue | ||
|
|
||
| const { data } = matter(raw) | ||
|
|
||
| results.push({ | ||
| ...(data as Omit<LatestVersion, "slug" | "version">), | ||
| version: folder, | ||
| slug: `/blog/${folder}`, | ||
| }) | ||
| } | ||
|
|
||
| const latest = | ||
| results.sort( | ||
| (a, b) => new Date(b.date ?? 0).getTime() - new Date(a.date ?? 0).getTime(), | ||
| )[0] ?? null | ||
|
|
||
| return latest | ||
| } |
There was a problem hiding this comment.
Since getLatestVersion is an asynchronous function, it is best practice to use asynchronous file system operations (fs/promises) to avoid blocking the Node.js event loop. Additionally, adding error handling for file access and parsing ensures the application remains robust if the directory structure or file content is unexpected.
import fs from "fs/promises"
import path from "path"
import matter from "gray-matter"
type LatestVersion = {
slug: string
version: string
date?: string
title?: string
type?: string
author?: string
description?: string
}
export const getLatestVersion = async (): Promise<LatestVersion | null> => {
const POSTS_DIR = path.join(process.cwd(), "src/app/blog/(post)")
try {
const stats = await fs.stat(POSTS_DIR)
if (!stats.isDirectory()) return null
} catch {
return null
}
const folders = await fs.readdir(POSTS_DIR)
const results: LatestVersion[] = []
for (const folder of folders) {
const fullPath = path.join(POSTS_DIR, folder, "page.mdx")
try {
const raw = await fs.readFile(fullPath, "utf-8")
const { data } = matter(raw)
results.push({
...(data as Omit<LatestVersion, "slug" | "version">),
version: folder,
slug: "/blog/" + folder,
})
} catch {
continue
}
}
return (
results.sort((a, b) => {
const timeA = a.date ? new Date(a.date).getTime() : 0
const timeB = b.date ? new Date(b.date).getTime() : 0
return timeB - timeA
})[0] ?? null
)
}
No description provided.