mdx-js / mdx

Markdown for the component era
https://mdxjs.com
MIT License
17.77k stars 1.14k forks source link

How to handle the following? #126

Closed khrome83 closed 6 years ago

khrome83 commented 6 years ago

This is a cool project, but it is unclear to me how to handle a few use cases. We use react-markdown currently, and moving to MDX with Next would be ideal, if it would support our needs.

Is there currently a way to do the following?

  1. Reference a string as the markdown content so the MD data can come from a source not controlled by babel/webpack. Our use case is that we have markdown coming from a external source in Contentful. Being able to make a call to retrieve the string and then import it would be amazing.

  2. Currently it seems like the way to replace the "renders" for the markdown import is per import basis because the act of importing is creating that JSX looking inclusion. It would be ideal to configure renderers across the entire application, and then override as needed. The use case for this - we use custom components for all markdown renderers, as this allows us to control styling in those components with styled-jsx. So we use the same paragraph, link, heading, etc render in each situation. But declaring it multiple times would be a lot of boilerplate code.

  3. This is less of a MDX issue, but may speak to providing a dynamic interface. Next.js has a wonderful static export setup, and it would be ideal if we could specify a dynamic page in next.js that takes a array of markdown files to create other pages. While this is a hurdle for Next.js, it seems that the import would require the ability to be dynamic, either opening the content seperatly as a string and feeding it in (#1) or some other interface.

Thanks! Just curious thoughts and if this aligns with the goals of the project.

soederpop commented 6 years ago

I kind of have the same question, I think.

I'd love if it I could access the original node from mdast's AST in my customer component renderer. It seems that it is using a transformed node instead from hast.

hawkins commented 6 years ago
  1. I haven't looked, but I think you may get away with this: https://github.com/mdx-js/mdx#sync-api . Just import mdx into your code and use it manually when you don't get source from your bundler.
  2. You could do this yourself, with a HOC or similar pattern:
    
    // lib/withComponents.js
    const default = { /* ... */ };
    const withComponents =
    (Mdx, overrides) => <Mdx components={Object.assign(default, overrides)} />

// index.js import hello from './hello.md' import withComponents from './lib/withComponents' const VanillaHello = withComponents(hello); const CustomizedHello = withComponents(hello, { h1: / ... / });

bryandowning commented 6 years ago

I'm also wondering about point 1. I tried using the sync API, but it produces a string of an ES module.

The MDX README lists "No runtime compilation" as a feature, so I'm guessing this isn't currently possible without babel/webpack.

@johno @timneutkens can you confirm?

timneutkens commented 6 years ago

I have drawn it out below 😄:

paper next js 3

Point 1: So runtime compilation is not possible at the moment. Also because we wouldn't know where the import statements come from and how to load them. You could compile external content at build time, however, this is not the responsibility of mdx, mdx takes an mdx string and turns it into an es6 module.

Point 2: like @hawkins said you can implement something yourself. In earlier versions, we depended on React context, but mdx can be compiled to any framework supporting JSX, so we just provide an explicit way to define components. If you want to magically inject components I would recommend doing either a HOC or creating a webpack loader that does this.

Point 3: I'm not sure what you mean exactly, but feel free to write a full spec on what you want in a Next.js issue. Please be very specific as to what you want it to look like so we can consider it 👍

silvenon commented 6 years ago

MDX has evolved since this discussion, documentation has improved, Next.js now has a MDX plugin etc. If there are any more questions, open an issue and I would be more than glad to explain everything. 😃

msrshahrukh100 commented 5 years ago

@silvenon Hi! Is the point 1 still not possible with mdx? Is there any other way you can suggest using which I can convert the markdown into JSX at runtime? My other question is, if the markdowns is converted to JSX at compile time, how is it done in the live code editor? Can we use a similar approach?

johno commented 5 years ago

👋 @msrshahrukh100

Fetching dynamic data and building pages is something that your framework needs to handle, it's slightly outside the scope of MDX core (though we should add docs that point people in the right direction).

Frameworks like Next.js, Gatsby, and React Static provide ways for you to fetch that data and then render MDX documents. I can't remember the last implementation I built with Next.js + Contentful exactly, but I was able to achieve it with a custom server and route setting based on that data for static exports.

With Gatsby + Contentful, you can use the data layer with a GraphQL source and then programmatically create pages using gatsby-mdx.

The live code editor uses: https://mdxjs.com/advanced/runtime

Vadorequest commented 4 years ago

@timneutkens @silvenon This issue is old and forgotten, but the new Next.js SSG support brings it back to life. Because it can compile stuff at build time, Next.js can now be used with MDX to build static pages based on MDX stored on a CMS. It's become technically possible, but there aren't any example of this yet.

Related issues:

Correct me if I'm wrong, but it should be possible now! And coupled with SSG, this opens up some very wide possibilities for ultra-rich content stored on CMS.

I don't know if it'll support advanced SSG features such as revalidate and fallback (but it should IMHO, since it's a full page rebuild, not some "on-the-fly" compilation).

silvenon commented 4 years ago

Yeah, I ran into this problem with Next.js as well when I tried to combine MDX with dynamic routes. I think the confusion happens if you forget to view MDX as a JavaScript module, which can happen. Markdown compiles to HTML, so it's totally something that you can put in a CMS, but as Tim illustrated, MDX is JavasScript, which is totally different even though the source file may look the same. Adding MDX content to a CMS makes as much sense as adding JavaScript. Maybe it would be possible to compile the MDX string with Babel and run the JavaScript code with some vm.Module acrobatics to get the exported component, but the point is that MDX is just not the right tool for this job.

Vadorequest commented 4 years ago

Thanks @silvenon for this clarification! I wish this was clearly stated in the docs as it was a great source of confusion to me.

Since then, I've found a way that doesn't use MDX but markdown-to-jsx and it works great. I'm able to store HTML/Markdown/JSX in Airtable (or any CMS fields text-based) and made a live example out of it on Next Right Now.

Demo: https://nrn-v2-mst-aptd-at-lcz-sty-c1.vercel.app/fr/examples/built-in-features/md-as-jsx Live example: https://nrn-v2-mst-aptd-at-lcz-sty-c1.vercel.app/fr/terms CMS: https://nrn.my.stacker.app/login?api_token=be1050d1-de5e-4ae0-97c8-030a132f254b&ref=unly-nrn Source code: https://github.com/UnlyEd/next-right-now/tree/v2-mst-aptd-at-lcz-sty

silvenon commented 4 years ago

Yay! I'm glad that you found a solution that works for you 👍

acaua commented 4 years ago

@silvenon @Vadorequest I think what you are discussing can be achieved with this library:

https://github.com/hashicorp/next-mdx-remote

What do you think?

Vadorequest commented 4 years ago

Thanks @acaua, I'm not using MDX for this anymore, and I believe using markdown-to-jsx has fewer downsides than MDX, due to the very way things are handled internally - But I could be wrong, it's only a personal feeling.

silvenon commented 4 years ago

I haven't checked how it works, but yes, next-mdx-remote looks ideal 😃 Reminds me of MDXRenderer from gatsby-plugin-mdx. And regarding markdown-to-jsx, if it works for you then that's the only thing that matters, and it's really lightweight so I bet it's much faster. One of the benefits of MDX is the access to the Unified ecosystem of plugins, and being able to import and export modules, i.e. Babel processing.