wooorm / xdm

Just a *really* good MDX compiler. No runtime. With esbuild, Rollup, and webpack plugins
http://wooorm.com/xdm/
MIT License
595 stars 18 forks source link

What to do if a remark plugin generates HTML nodes? #105

Closed silvenon closed 2 years ago

silvenon commented 2 years ago

Hi! ❤️

I'm trying to use @atomiks/mdx-pretty-code with xdm, but I'm getting raw errors similar to the ones in #90 because that plugin generates html nodes for code blocks. I re-read https://github.com/wooorm/xdm/issues/90#issuecomment-944901432 a few times, but I couldn't quite figure out what the best thing to do is, excuse me for repeating a similar issue. The only thing that worked is converting all html nodes into mdxJsxFlowElement nodes, but it seems clumsy and like I'm lacking some fundamental understanding of the problem.

Help? 🙏

npm install xdm @atomiks/mdx-pretty-code shiki
import fs from 'node:fs/promises'
import { compile } from 'xdm'
import { createRemarkPlugin } from '@atomiks/mdx-pretty-code'

const prettyCode = createRemarkPlugin({
  shikiOptions: {
    theme: JSON.parse(
      await fs.readFile('node_modules/shiki/themes/github-light.json', 'utf8')
    )
  }
})

const mdxContent = `
~~~js
console.log('Hello World')
~~~
`.trim()

const result = await compile(mdxContent, {
  remarkPlugins: [prettyCode],
})

console.log(String(result))
ChristianMurphy commented 2 years ago

Hey @silvenon! :wave: Long time no see, how are you?

I'm getting raw errors

rehype-raw can help https://github.com/rehypejs/rehype-raw it re-parses the raw/html nodes into an HTML AST (hast) which XDM can process For example: https://stackblitz.com/edit/node-ccmljd?file=index.js

source from sandbox ```js import fs from 'node:fs/promises'; import { compile } from 'xdm'; import { createRemarkPlugin } from '@atomiks/mdx-pretty-code'; import rehypeRaw from 'rehype-raw'; const prettyCode = createRemarkPlugin({ shikiOptions: { theme: JSON.parse( await fs.readFile('node_modules/shiki/themes/github-light.json', 'utf8') ), }, }); const mdxContent = ` ~~~js console.log('Hello World') ~~~ `.trim(); const result = await compile(mdxContent, { remarkPlugins: [prettyCode], rehypePlugins: [rehypeRaw], }); console.log(String(result)); ```
silvenon commented 2 years ago

Hey @ChristianMurphy! I'm doing great, you? 😄

Thanks for your reply! I forgot to say, rehype-raw fails on mdxJsxFlowElement nodes, so it would fail as soon as you put some JSX in mdxContent. Should I create a custom rehype plugin that runs rehype-raw selectively like this?

const rehypeMdxRaw = () => tree => {
  visit(tree, (node, index, parent) => {
    if (node.type === 'raw') {
      parent.children[index] = rehypeRaw()(node)
    }
  })
}
silvenon commented 2 years ago

Oh, I just discovered the passThrough option!

const result = await compile(mdxContent, {
  remarkPlugins: [prettyCode],
  rehypePlugins: [[rehypeRaw, { passThrough: ['mdxJsxFlowElement'] }]],
});

Excellent!

ChristianMurphy commented 2 years ago

I'm doing great, you?

Good to hear! I'm well also.

I just discovered the passThrough option!

Indeed, pass through should do the trick :sparkles: