Skip to content

Instantly share code, notes, and snippets.

@jasikpark
Created October 31, 2022 16:57
Show Gist options
  • Save jasikpark/7f971857d55a6548aae8f183c47d3b5d to your computer and use it in GitHub Desktop.
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
---
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