Remix

Rendering with

Rendering with Remix requires a couple of steps.

View on

Server modules

To prevent server modules in the client bundle, use file names.

Create a file named mdx-butler.server.ts.

export { docs, createFrontmatterProcessor } from 'mdx-butler';

Page

Import the previously created server exports in your page.

Remix uses a to load page data.

import { json, LoaderFunctionArgs, MetaFunction } from '@remix-run/node';
import { docs } from '../mdx-butler.server';
import { useLoaderData } from '@remix-run/react';
import { getMDXComponent } from 'mdx-butler/client';

type Frontmatter = {
  title: string;
};

export async function loader({ params: { slug } }: LoaderFunctionArgs) {
  return json((await docs<Frontmatter>()).find((x) => slug === x.path));
}

export const meta: MetaFunction<typeof loader> = ({ data }) => {
  return [
    { title: data?.frontmatter.title },
    { name: 'description', content: data?.frontmatter.description },
  ];
};

export default function Index() {
  const doc = useLoaderData<typeof loader>();

  if (!doc) return <div>not found</div>;

  const Component = getMDXComponent(doc.code);

  return (
    <div
      style={{
        display: 'flex',
        gap: '1rem',
        flexDirection: 'row',
      }}
    >
      <div>
        <h1>{doc.frontmatter.title}</h1>
        <Component />
      </div>
      <div
        style={{
          display: 'flex',
          gap: '1rem',
          flexDirection: 'column',
        }}
      >
        <h2>On this page</h2>
        {doc.headings.map((x) => (
          <a key={x.title} href={`#${x.title}`}>
            {x.title}
          </a>
        ))}
      </div>
    </div>
  );
}