Next.js Discord

Discord Forum

How can I import mdx file staticly in App Router?

Answered
Cornish Rex posted this in #help-forum
Open in Discord
Avatar
Cornish RexOP
I have mdx files in my writings/_posts directory. When I'm using like this nextjs creating server rendered pages. How can I change it to static generation.

import { compileMDX } from "next-mdx-remote/rsc";
import path from "path";
import { readFile, access, readdir } from "fs/promises";
import { notFound } from "next/navigation";

const POSTS_FOLDER = path.join(process.cwd(), "app/writings/_posts");

async function readPostFile(slug: string) {
  const filePath = path.resolve(path.join(POSTS_FOLDER, '${slug}.mdx'));

  try {
    await access(filePath);
  } catch (err) {
    return null;
  }

  const fileContent = await readFile(filePath, { encoding: "utf8" });
  return fileContent;
}

export default async function getMdxDatas({
  params,
}: {
  params: { slug: string };
}) {
  const markdown = await readPostFile(params.slug);

  if (!markdown) {
    notFound();
  }

  const { content, frontmatter } = await compileMDX<{ title: string,date:Date }>({
    source: markdown,
    options: { parseFrontmatter: true },
  });

  // do something with frontmatter, like set metadata or whatever
  return {
    content,
    frontmatter,
    nextLink: "nextLink",
    previousLink: "previousLink",
  };
}

// get all slugs title and summary

export const getFiles = async () => {
  const files = path.resolve(POSTS_FOLDER);
  const fileNames = await readdir(files);

  const data = await Promise.all(
    fileNames.map(async (fileName) => {
      const filePath = path.resolve(POSTS_FOLDER, fileName);
      const fileContent = await readFile(filePath, { encoding: "utf8" });
      const { frontmatter } = await compileMDX<{
        title: string;
        summary: string;
        date: string;
        image: string;
        slug: string;
      }>({
        source: fileContent,
        options: { parseFrontmatter: true },
      });
      return {
        title: frontmatter.title,
        summary: frontmatter.summary,
        date: frontmatter.date,
        image: frontmatter.image,
        slug: fileName.replace(".mdx", ""),
      };
    })
  );
  return data;
};

export const getFilesWithCount = async (count: number) => {
  const files = path.resolve(POSTS_FOLDER);
  const fileNames = await readdir(files);

  const data = await Promise.all(
    fileNames.map(async (fileName) => {
      const filePath = path.resolve(POSTS_FOLDER, fileName);
      const fileContent = await readFile(filePath, { encoding: "utf8" });
      const { frontmatter } = await compileMDX<{
        title: string;
        summary: string;
        date: string;
        image: string;
        slug: string;
      }>({
        source: fileContent,
        options: { parseFrontmatter: true },
      });
      return {
        title: frontmatter.title,
        summary: frontmatter.summary,
        date: frontmatter.date,
        image: frontmatter.image,
        slug: fileName.replace(".mdx", ""),
      };
    })
  );
  return data.slice(0, count);
}

And then i'm using readMdxFile function in my slug.
import getMdxDatas from "@/lib/readMdxFile";

export default async function PostPage({
  params,
}: {
  params: { slug: string };
}) {
  const { content, frontmatter, nextLink, previousLink } = await getMdxDatas({
    params,
  });

  return (
    <>
         {content}
    </>
  );
}
Image
Answered by not-milo.tsx
My bad. The link is this one then: https://nextjs.org/docs/app/api-reference/functions/generate-static-params

You have to use generateStaticParams to tell Next what slugs to generate at build time.

As for the data that goes in them you can keep fetching it as you're doing right now.
View full answer

8 Replies

Avatar
not-milo.tsx
You should be using getStaticProps and getStaticPaths to tell Next what data and pages to generate at build time. Without them it will default to SSR cause it has no knowledge of what slugs might be passed to your post page.

See: https://nextjs.org/docs/pages/building-your-application/rendering/static-site-generation#static-generation-with-data

Btw, I highly recommend switching to the new app router if you want to future-proof your website.
Avatar
Cornish RexOP
Thanks for your reply, actually I'm using app router, and I want to generate static pages from my local mdx files.
I'm using next-mdx-remote when I'm importing mdx files
Avatar
not-milo.tsx
My bad. The link is this one then: https://nextjs.org/docs/app/api-reference/functions/generate-static-params

You have to use generateStaticParams to tell Next what slugs to generate at build time.

As for the data that goes in them you can keep fetching it as you're doing right now.
Answer
Avatar
Cornish RexOP
Thanks a lot, I will try this 🙏🏻
Avatar
Cornish RexOP
It's worked for my writings page but I didn't figure out how can I use ssg for my homepage. https://nextjs-forum.com/post/1214572991242051594
Avatar
not-milo.tsx
Great! Just a note tho, cross posting goes against the rules of the server :box_cat_hide:
Avatar
Tonkinese
You can always try one of their exports... I think it's something like forceStatic=true, but you should definitely look that up, but at the same time that's not really the best approach if there's a legit reason they can't generate the site statically.