kentcdodds / mdx-bundler

ðŸĶĪ Give me MDX/TSX strings and I'll give you back a component you can render. Supports imports!
MIT License
1.79k stars 75 forks source link

How to convert dynamic data to MDX #55

Open belkocik opened 3 years ago

belkocik commented 3 years ago

Hello, I got data on GraphCMS in markdown text and I'd like to convert it to MDX. Could you tell me how to do it? I've installed mdx-bundler. content: portfolioItem.portfolios[0].content, // <--- it containts the markdown text from GraphCMS. I tried with mdx-remote but there were errors with severity vulnerabilities

I got

import { bundleMDX } from "mdx-bundler";

export const getStaticProps = async ({ params }) => {
  const portfolioItem = await getPortfolioItem(params.slug);
  return {
    props: {
      portfolioItem: portfolioItem.portfolios[0],
      content: portfolioItem.portfolios[0].content,
    },
  };
};

export default function Home({ portfolioItem, content }) {
  console.log(portfolioItem);
  return (
        <div className="prose prose-xl max-w-none mt-4 text-justify  dark:text-gray-100 mb-10">
          {content}
        </div>
  );
}
Arcath commented 3 years ago

mdx-bundler can absolutely take a string from your CMS and bundle it!

In your getStaticProps you need to use bundleMDX to turn the string into a bundle, then pass it through props

const {code} = await bundleMDX(portfolioItem.portfolios[0].content)

return {
  props: {
    portfolioItem: portfolioItem.portfolios[0],
    code,
  },

Then add import {getMDXComponent} from 'mdx-bundler/client' to your page and output it like so:

export default function Home({ portfolioItem, content }) {
  const Component = React.useMemo(() => getMDXComponent(code), [code])
  return (
        <div className="prose prose-xl max-w-none mt-4 text-justify  dark:text-gray-100 mb-10">
          <Component />
        </div>
  );
}

There are a whole host of options that can improve the way MDX is handled depending on your needs which you can find here: https://github.com/kentcdodds/mdx-bundler#options

belkocik commented 3 years ago

Thank you for your reply :). I got error when I click the post with markdown text:

Error: Build failed with 1 error:
__mdx_bundler_fake_dir__/_mdx_bundler_entry_point.mdx:23:55: error: [plugin: esbuild-xdm] Could not parse expression with acorn: Unexpected token

This error happened while generating the page. Any console logs will be displayed in the terminal window.

my 23 line is: const { code } = await bundleMDX(portfolioItem.portfolios[0].content);

my [slug].js file: https://codepen.io/belkocik/pen/JjWemMV

Arcath commented 3 years ago

Sounds like an error in the MDX, what is line 23 excluding any frontmatter, of the MDX you are getting from your cms?

belkocik commented 3 years ago

You mean what I got in content section in my graphCMS?

# Risus varius ad magna consequat sociosqu mol

Lorem ipsum dolor sit amet consectetur adipiscing elit hac per gravida ac, sed accumsan justo diam bibendum molestie feugiat nec nunc vehicula. Pulvinar tempus ante sociosqu litora ultrices sagittis lacus euismod purus tempor, risus rhoncus egestas nec penatibus aliquam ligula elementum. Posuere platea pretium commodo arcu viverra cubilia lectus, euismod eros mi maecenas quam sodales class porta, mattis a potenti risus consequat ligula. 

Ut sodales consequat augue nam integer curae cursus aliquet natoque vehicula euismod, orci eleifend ridiculus vitae quis laoreet ultricies placerat fames habitant libero, varius curabitur felis justo magnis imperdiet aptent lacus porttitor porta. Dignissim pharetra convallis augue bibendum enim commodo molestie ridiculus, condimentum potenti hendrerit primis libero orci imperdiet sapien, nostra vivamus et pellentesque parturient penatibus taciti. Senectus lacus scelerisque feugiat interdum vivamus proin massa parturient, justo pulvinar ornare sapien facilisis hendrerit in class, magna euismod vestibulum mollis natoque facilisi dictumst. 

## Dui aliquam eu imperdiet egestas ul

- Vehicula ad nulla neque torquent, interdum himenaeos tortor.

- Neque senectus feugiat varius eros, ut purus scelerisque.

- Vitae magnis varius nec in, accumsan dui auctor.

- Pellentesque laoreet sapien litora fusce hac, dictum nibh curae.

Feugiat fringilla consequat nascetur nisi in nulla aenean curae at aptent, ad leo placerat varius urna est vel rhoncus rutrum tincidunt, maecenas nostra nisl conubia fermentum blandit ligula orci semper. Conubia pretium pulvinar phasellus sollicitudin sociosqu lectus proin justo placerat auctor, sociis senectus libero pharetra cum parturient erat a faucibus vehicula etiam, laoreet velit nisl platea dictumst fusce fringilla semper tincidunt. 

First he wanted to stand up quietly and undisturbed, get dressed, above all have breakfast, and only then consider further action, for (he noticed this clearly) by thinking things over in bed he would not reach a reasonable conclusion. He remembered that he had already often felt a light pain or other in bed, perhaps the result of an awkward lying position, which later turned out to be purely imaginary when he stood up, and he was eager to see how his present fantasies would gradually dissipate. That the change in his voice was nothing other than the onset of a real chill, an occupational illness of commercial travelers, of that he had not the slightest doubt.

    function metamorphose(protagonist,author){
        if( protagonist.name.first === 'Gregor' && author.name.last === 'Kafka' ){
            protagonist.species = 'insect';
        }
    }

from my VSCode terminal:

> __mdx_bundler_fake_dir__/_mdx_bundler_entry_point.mdx:23:46: error: [plugin: esbuild-xdm] Could not parse expression with acorn: Unexpected token
    23 │     function metamorphose(protagonist,author){
Error: Build failed with 1 error:
__mdx_bundler_fake_dir__/_mdx_bundler_entry_point.mdx:23:55: error: [plugin: esbuild-xdm] Could not parse expression with acorn: Unexpected token
    at failureErrorWithLog (C:\Users\bubuq3\Desktop\Next.js-portfolio\portfolio-cms\node_modules\esbuild\lib\main.js:1449:15)
    at C:\Users\bubuq3\Desktop\Next.js-portfolio\portfolio-cms\node_modules\esbuild\lib\main.js:1131:28
    at runOnEndCallbacks (C:\Users\bubuq3\Desktop\Next.js-portfolio\portfolio-cms\node_modules\esbuild\lib\main.js:921:63)
    at buildResponseToResult (C:\Users\bubuq3\Desktop\Next.js-portfolio\portfolio-cms\node_modules\esbuild\lib\main.js:1129:7)
    at C:\Users\bubuq3\Desktop\Next.js-portfolio\portfolio-cms\node_modules\esbuild\lib\main.js:1236:14
    at C:\Users\bubuq3\Desktop\Next.js-portfolio\portfolio-cms\node_modules\esbuild\lib\main.js:609:9
    at handleIncomingPacket (C:\Users\bubuq3\Desktop\Next.js-portfolio\portfolio-cms\node_modules\esbuild\lib\main.js:706:9)
    at Socket.readFromStdout (C:\Users\bubuq3\Desktop\Next.js-portfolio\portfolio-cms\node_modules\esbuild\lib\main.js:576:7)
    at Socket.emit (events.js:315:20)
    at addChunk (internal/streams/readable.js:309:12)
    at readableAddChunk (internal/streams/readable.js:284:9)
    at Socket.Readable.push (internal/streams/readable.js:223:10)
    at Pipe.onStreamRead (internal/stream_base_commons.js:188:23) {
  errors: [
    {
      detail: [Error],
      location: [Object],
      notes: [],
      pluginName: 'esbuild-xdm',
      text: 'Could not parse expression with acorn: Unexpected token'
    }
  ],
  warnings: []
}
Arcath commented 3 years ago

MDX doesn't support indented code like that, wrapping it in js</code> and <code> fixes the problem for me.

belkocik commented 3 years ago

I removed from my CMS

    function metamorphose(protagonist,author){
        if( protagonist.name.first === 'Gregor' && author.name.last === 'Kafka' ){
            protagonist.species = 'insect';
        }
    }

and this looks like this: It hasn't converted it to markdown image

Arcath commented 3 years ago

What does the HTML look like? Has it put in <p> and <h2> tags? I know tailwind resets everything to a level playing field so it may just be a styling issue.

belkocik commented 3 years ago

Yes when I click f12 and inspect that there are ul,li, p tags ;/ image

Arcath commented 3 years ago

Looks like mdx-bundler is doing its job :)

Is tailwind-typography installed and configured?

belkocik commented 3 years ago

Thank you, everything works right now 👍 appreciate your help 😄 btw. is it possible to highlight the syntax in js? there is just gray color of the text :(


    function metamorphose(protagonist,author){
        if( protagonist.name.first === 'Gregor' && author.name.last === 'Kafka' ){
            protagonist.species = 'insect';
        }
    }

image

image

Arcath commented 3 years ago

Syntax highlight is possible with a remark plugin, I use remarkHighlight to do it on my site

belkocik commented 3 years ago

Got an error:

Error: Additional keys were returned from `getStaticProps`. Properties intended for your component must be nested under the `props` key, e.g.:

    return { props: { title: 'My Title', content: '...' } }
export const getStaticProps = async ({ params }) => {
  const portfolioItem = await getPortfolioItem(params.slug);
  const { code } = await bundleMDX(portfolioItem.portfolios[0].content, {
    xdmOptions(options) {

      options.remarkPlugins = [
        ...(options.remarkPlugins ?? []),
        remarkHighlight,
      ];

      return options;
    },
  });

  return code;
};
Arcath commented 3 years ago

The return from getStaticProps needs to be an object with a props object that gets passed to your component

for example:


export const getStaticProps = async ({ params }) => {
  const portfolioItem = await getPortfolioItem(params.slug);
  const { code } = await bundleMDX(portfolioItem.portfolios[0].content, {
    xdmOptions(options) {

      options.remarkPlugins = [
        ...(options.remarkPlugins ?? []),
        remarkHighlight,
      ];

      return options;
    },
  });

  return {props: {code}};
};
``
belkocik commented 3 years ago

Got it like: image

im my GraphCMS: content section i got:

js~~~

    function metamorphose(protagonist,author){
        if( protagonist.name.first === 'Gregor' && author.name.last === 'Kafka' ){
            protagonist.species = 'insect';
        }
    }
~~~

And it still doesn't highlight the code as it is javascript syntax.

export const getStaticProps = async ({ params }) => {
  const portfolioItem = await getPortfolioItem(params.slug);
  const { code } = await bundleMDX(portfolioItem.portfolios[0].content, {
    xdmOptions(options) {
      options.remarkPlugins = [
        ...(options.remarkPlugins ?? []),
        remarkHighlight,
      ];

      return options;
    },
  });

  return { props: { code, portfolioItem: portfolioItem.portfolios[0] } };
};

I've imported: import remarkHighlight from "remark-highlight.js"; and that is how I pass it:

export default function Home({ portfolioItem, content, code }) {

  const Component = React.useMemo(() => getMDXComponent(code), [code]);

 return (
     <div className="prose prose-xl max-w-none mt-4 text-justify dark:text-gray-100 mb-10 cms-content">
            <Component />
          </div>
)
}