← Back to Archive

Migrating My Blog to MDX and Shiki

I recently migrated my blog from markdown to MDX with Shiki syntax highlighting. The old setup used vite-plugin-markdown and react-syntax-highlighter, but I wanted VS Code-quality highlighting and the ability to use JSX components in blog posts.

Configure Vite for MDX:

export default defineConfig(async () => {
  const mdx = await import("@mdx-js/rollup");
  return {
    plugins: [
      react(),
      mdx.default({
        providerImportSource: "@mdx-js/react",
        remarkPlugins: [
          (await import("remark-frontmatter")).default,
          (await import("remark-mdx-frontmatter")).default,
        ],
      }),
    ],
  };
});

Create a Shiki component for code highlighting:

export const CodeBlock = (props) => {
  const isLightTheme = useAtomValue(isLightThemeAtom);
  const { children, className } = props;
  const language = className?.replace("language-", "") || "text";

  return (
    <ShikiHighlighter
      language={language}
      theme={{
        light: "github-light",
        dark: "github-dark",
      }}
      defaultColor={isLightTheme ? "light" : "dark"}
    >
      {children.trim()}
    </ShikiHighlighter>
  );
};

Convert files by renaming .md to .mdx. Frontmatter stays exactly the same. Update the blog component to use MDX imports instead of the markdown plugin.

The result is VS Code-quality syntax highlighting, cleaner architecture, and the ability to use React components directly in blog posts.