kentcdodds / mdx-bundler

šŸ¦¤ Give me MDX/TSX strings and I'll give you back a component you can render. Supports imports!
MIT License
1.78k stars 75 forks source link

`source` or `file` must be defined #163

Closed yunesco closed 2 years ago

yunesco commented 2 years ago

Relevant code or config

import matter from 'gray-matter';
import { join } from 'path';
import readingTime from 'reading-time';
import { readdirSync, readFileSync } from 'fs';
import { bundleMDX } from 'mdx-bundler';
import rehypeSlug from 'rehype-slug';
import rehypeCodeTitles from 'rehype-code-titles';
import rehypeAutolinkHeadings from 'rehype-autolink-headings';
import rehypePrism from 'rehype-prism-plus';

const contentPath = 'content/books';

export async function getFiles() {
  return readdirSync(join(process.cwd(), contentPath));
}

export async function getFileBySlug(slug) {
  // we will pass in a slug of the page we want like /blogs/blog-1
  // example and we will get the parsed content for that particular
  // blog page.

  const source = readFileSync(join(process.cwd(), contentPath, `${slug}.mdx`), 'utf8');

  const { code, frontmatter } = await bundleMDX(source, {
    xdmOptions(options) {
      options.rehypePlugins = [
        ...(options?.rehypePlugins ?? []),
        rehypeSlug,
        rehypeCodeTitles,
        rehypePrism,
        [
          rehypeAutolinkHeadings,
          {
            properties: {
              className: ['anchor'],
            },
          },
        ],
      ];
      return options;
    },
  });

  return {
    // return the parsed content for our page along with it's metadata
    // we will be using gray-matter for this.
    code,
    frontMatter: {
      wordCount: source.split(/\s+/gu).length,
      readingTime: readingTime(source),
      slug: slug || null,
      ...frontmatter,
    },
  };
}

export async function getAllFilesFrontMatter() {
  const files = readdirSync(join(process.cwd(), contentPath));

  return files.reduce((allposts, postSlug) => {
    // returns the parsed data for all the files within the posts directory
    const source = readFileSync(join(process.cwd(), contentPath, postSlug), 'utf8');
    const { data } = matter(source);

    return [
      {
        ...data,
        // we will be using the filename by removing the extension
        // as our slug for the file.
        slug: postSlug.replace('.mdx', ''),
        readingTime: readingTime(source),
      },
      ...allposts,
    ];
  }, []);
}

What you did: this code works fine on mdx-bundler 7.0.0 but when i upgrade to the latest version i get the error below

Screenshot 2022-03-27 at 14 00 34

Reproduction repository:

Problem description:

Suggested solution: I am not sure whats the solution

kamroot commented 2 years ago

Version 8.0 was a breaking change. You have to change your code to pass the source as part of the object sent to bundleMDX. Simple change - like following

 const { code, frontmatter } = await bundleMDX({
    source: source,
    xdmOptions(options) {
      options.rehypePlugins = [
        ...(options?.rehypePlugins ?? []),
In the above snippet we removed the `source` option as the first argument and it is now inside the object passed to bundleMDX.
yunesco commented 2 years ago

@kamroot That fixed it, thanks!

kamroot commented 2 years ago

If that is what you want to do, I'd just import the other mdx file from your original mdx file. For example from content/books/index.mdx you can import content/blogs/index.mdx (an example, obviously).