I’m trying to migrate my portfolio website (https://meje.dev) to use the recent version of Next.js and Typescript, plus a couple of improvements on my end too.
For my blog, I’m using next-mdx-remote and node’s filesystem module to read posts from my project.
When I run the dev server locally, and I click on a PostCard to view the article, the dynamic route renders my markdown content.
When I run the build locally too, it runs quite fine and completes the entire step without errors. But when I try to access any article in production, I’m met with a 404 page. I’m very confused, because this is almost the same thing (except the typescript migration) that powers the current website
Here’s the new site: https://sev-demo.vercel.app/
I’ve also tried adding a pageExtensions property to my nextConfig, but it’s still the same.
Here’s an excerpt of what my slug route looks like:
export type Post = {
source: MDXRemoteSerializeResult<
Record<string, unknown>,
Record<string, unknown>
>;
tableOfContent: Heading;
updatedAt: string;
frontmatter: PostFrontmatter;
};
export default function BlogPost({ post }: { post: Post }) {
return (
<>
<MetaData
pageTitle={post.frontmatter.title}
/>
<Layout>
<Box display="flex" flexFlow="column" gap="1em">
<Box className="content" pb="1.4em">
<MDXRemote {...post.source} />
</Box>
</Box>
</Layout>
</>
);
}
export async function getStaticProps(context: GetStaticPropsContext) {
const slug = context?.params && context?.params.slug;
const { content, frontmatter } = await getPostFromSlug(String(slug));
const markdownHeadings = extractHeadings(`posts/${slug}.mdx`);
const lastModified = await getLastModified(`posts/${slug}.mdx`);
const posts = await getPosts();
const rpcOptions = {
theme: "aurora-x",
keepBackground: false,
defaultLang: {
block: "javascript",
inline: "plaintext",
},
filterMetaString: (str: string) => str.replace(/filename="[^"]*"/, ""),
};
const mdxSource = await serialize(content, {
mdxOptions: {
rehypePlugins: [
rehypeSlug,
[
rehypeAutolinkHeadings,
{
properties: { className: ["anchor"] },
},
{ behaviour: "wrap" },
],
[rehypePrettyCode, rpcOptions],
rehypeCodeTitles,
],
},
});
return {
props: {
post: {
frontmatter,
source: mdxSource,
tableOfContents: markdownHeadings,
updatedAt: lastModified?.toDateString(),
},
},
};
}
export async function getStaticPaths() {
// prerender all pages
// (slower builds, but faster initial page load)
// const paths = (await getPostSlugs()).map((slug) => ({ params: { slug } }));
return {
paths: [],
fallback: false,
};
}