Created
October 31, 2022 16:57
-
-
Save jasikpark/7f971857d55a6548aae8f183c47d3b5d to your computer and use it in GitHub Desktop.
Showing an attempt at a type-safe MD + MDX glob and sort for a blog
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
import BlogIndex from "@layouts/BlogIndex.astro"; | |
import BlogPost from "@layouts/BlogPost.astro"; | |
import { assert } from "assert-ts"; | |
import type { MarkdownInstance, MDXInstance, Page, PaginateFunction } from "astro"; | |
import type { AstroComponentFactory } from "astro/dist/runtime/server"; | |
import BlogMeta from "./meta.json"; | |
import type { MarkdownFrontmatter } from "@data/posts/MarkdownFrontmatter"; | |
type MarkdownOrMDXInstance = | |
| MarkdownInstance<MarkdownFrontmatter> | |
| MDXInstance<MarkdownFrontmatter>; | |
type PartialMarkdownOrMDXInstance = | |
| MarkdownInstance<Partial<MarkdownFrontmatter>> | |
| MDXInstance<Partial<MarkdownFrontmatter>>; | |
export async function getStaticPaths({ paginate }: { paginate: PaginateFunction }) { | |
// get all posts that have a slug and date and aren't hidden, and sort by date. | |
const allMdPages = (await Astro.glob<MarkdownFrontmatter>( | |
"../../data/posts/*.md" | |
)) as MarkdownInstance<Partial<MarkdownFrontmatter>>[]; | |
const allMdxPages = (await Astro.glob<MarkdownFrontmatter>( | |
"../../data/posts/**/*.mdx" | |
)) as MDXInstance<Partial<MarkdownFrontmatter>>[]; | |
const allPages = ([...allMdPages, ...allMdxPages] as PartialMarkdownOrMDXInstance[]) | |
.filter(function (post): post is MarkdownOrMDXInstance { | |
const missingError = (prop: string) => `post ${post.file.toString()} has no ${prop}`; | |
assert(post.frontmatter.title, missingError("title")); | |
assert(post.frontmatter.summary, missingError("summary")); | |
assert(post.frontmatter.hero, missingError("hero")); | |
assert(post.frontmatter.hero?.src, missingError("hero.src")); | |
assert(post.frontmatter.hero?.alt, missingError("hero.alt")); | |
return !!post.frontmatter.slug && !!post.frontmatter.date && !post.frontmatter.hide; | |
}) | |
.sort( | |
(a, b) => new Date(b.frontmatter.date).valueOf() - new Date(a.frontmatter.date).valueOf() | |
); | |
// generate paths for the blog posts | |
const postPaths = allPages.map(({ Content, frontmatter }: MarkdownOrMDXInstance) => { | |
return { | |
params: { | |
page: frontmatter.slug, | |
}, | |
props: { | |
page: { | |
...frontmatter, | |
Content, | |
isPost: true, | |
}, | |
}, | |
}; | |
}); | |
// generate paths for the blog index pages | |
// @ts-expect-error the return type of `paginate` is too generic here, so we use `unknown` to shut up ts | |
const paginationPaths = paginate(allPages, { pageSize: 10 }) as Page<MarkdownOrMDXInstance>[]; | |
return [...paginationPaths, ...postPaths]; | |
} | |
type Post = MarkdownFrontmatter & { Content: AstroComponentFactory; isPost: true }; | |
type PaginationPage = Page<MarkdownOrMDXInstance> & { isPost: undefined }; | |
type Props = { | |
page: Post | PaginationPage; | |
}; | |
const { page } = Astro.props as Props; | |
--- | |
{page.isPost ? ( | |
<BlogPost content={page}> | |
<page.Content /> | |
</BlogPost> | |
) : ( | |
<BlogIndex | |
meta={{ title: assert(BlogMeta.title), description: assert(BlogMeta.description) }} | |
page={page} | |
/> | |
)} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment