stefanprobst / rehype-extract-toc

MIT License
18 stars 0 forks source link

[Question] How can you access the VFile attribute? #6

Closed max-pod closed 2 years ago

max-pod commented 2 years ago

Hello, I'm sorry but I'm lost in how to access the VFile attribute.

Trying to use Next-MDX-Remote, and I'm just missing what I have to log out to find it, and I'm just lost. https://github.com/hashicorp/next-mdx-remote/blob/acbcff81a445d20337996b490a15b7172d435c2f/src/serialize.ts#L77

I'm probably just missing something, but this plugin seems to be exactly what I need. Thank you for any help!

stefanprobst commented 2 years ago

hi, i haven't personally used next-mdx-remote so i might be missing something but from a quick look it seems like it does not give you access to the vfile data. (quickly checked with next-mdx-remote@next as well). also it does not look like there is a way to access any added exports (which is the alternative way this plugin provides).

it might be easier to just use mdx directly? in next.js it would looks something like this (this shows both options: exposing the table of contents via vfile data, and additionally adding it as a named export to the mdx document:

// src/pages/index.js

import { compile, runSync, run } from '@mdx-js/mdx'
import withToc from '@stefanprobst/rehype-extract-toc'
import withTocExport from '@stefanprobst/rehype-extract-toc/mdx'
import { Fragment, useEffect, useMemo, useState } from 'react'
import * as runtime from 'react/jsx-runtime'

const md = `
# Title

Text

## Heading 1

Text

## Heading 2

Text
`

export async function getStaticProps() {
  const vfile = await compile(md, {
    rehypePlugins: [
      withToc,
      withTocExport,
    ],
    outputFormat: 'function-body',
  })
  const toc = vfile.data.toc
  const content = String(vfile)

  return { props: { content, toc } }
}

export default function HomePage({ content, toc }) {
  const { Content, meta } = useMdxAsync(content)
  // const { Content, meta } = useMdxSync(content)

  return (
    <main>
      <pre>{JSON.stringify(toc, null, 2)}</pre>
      <pre>{JSON.stringify(meta.tableOfContents, null, 2)}</pre>
      <Content />
    </main>
  )
}

function useMdxAsync(content) {
  const [result, setResult] = useState({ Content: Fragment, meta: {} })

  useEffect(() => {
    async function _run() {
      const { default: Content, ...meta } = await run(content, runtime)
      setResult({ Content, meta })
    }

    _run()
  }, [content])

  return result
}

// function useMdxSync(content) {
//   return useMemo(() => {
//     const { default: Content, ...meta } = runSync(content, runtime)
//     return { Content, meta }
//   }, [content])
// }
max-pod commented 2 years ago

Thanks you for the help!

I figured something was missing.