hashicorp / next-mdx-remote

Load MDX content from anywhere
Mozilla Public License 2.0
2.71k stars 141 forks source link

How to get vfile.data from the serializer? #270

Open nightire opened 2 years ago

nightire commented 2 years ago

I'm using a remark plugin to extract all headings and store them in the vfile.data, but the problem is the serializer only returns the vfile.data.matter so it's impossible to get more from vfile.data:

image

So, what should I do to get the extra things from vfile.data?

BRKalow commented 2 years ago

We could pass along the vfile data in scope, what do you think about that?

nightire commented 2 years ago

We could pass along the vfile data in scope, what do you think about that?

Yes, that would be great, thanks.

kxxt commented 2 years ago

We could pass along the vfile data in scope, what do you think about that?

Maybe it's better not to expose the vfile data in scope. Personally I just want to extract some useful info from it, but I don't want to pass them to MDX. We can pass that data through a new variable.

Edit: It would be a breaking change if fields in vfile.data overwrite some fields in scope parameter.

jesstelford commented 1 year ago

Since serialize accepts a VFileCompatible, you're able to pass in your own vfile, then later extract the data yourself:

const file = new VFile('**some** awesome `content`');
const mdx = serialize(file);
// file.data has your remark plugin's data
talatkuyuk commented 8 months ago

Since serialize accepts a VFileCompatible, you're able to pass in your own vfile, then later extract the data yourself:

const file = new VFile('**some** awesome `content`');
const mdx = serialize(file);
// file.data has your remark plugin's data

You are right @jesstelford, but it is viable for only pages router since you can sent the data to client and inject it into MDX within the scope. It is not possible to pass file.data into the MDX within the scope especially for the app router. So, the requested feature still can be useful.

Moriarty47 commented 7 months ago

Any updates ?

Edit Actually, I am using a 'hacker' way to do this for now. Code snippets as follow.

// processMarkdown.ts
const extraData = { headings: null };
const compiled = await compileMDX({
  source: 'some content',
  options: {
    mdxOptions: {
      rehypePlugins: [
        [customPlugin, {
          callback(headings) {
            extraData.headings = headings;
          }
        }]
      ],
    },
  },
});

// customPlugin.ts
const customPlugin: Plugin<
  [Partial<customPluginOptions>?],
  Root
> = (options = {}) => {
  const _options = normalizeOptions(options);
  return (tree: Root) => {
    const headings = getHeadings(tree, _options);
    const toc = createToc(headings, _options);
    if (_options.addToDoc) {
        insertTOC(toc, _options);
      }
    } else {
      _options.callback?.(toc);
    }
    return tree;
  };
};
talatkuyuk commented 7 months ago

I would like to inform that the next-mdx-remote-client supports copying data from vfile.data into scope.

// ...

const options: SerializeOptions = {
  // ...
  vfileDataIntoScope: ["toc"], // the plugin "remark-flexible-toc" produces vfile.data.toc
  mdxOptions: {
    // ...
    remarkPlugins: [remarkFlexibleToc],
  },
};

const mdxSource = await serialize({ source, options });

Now, the scope has toc (mdxSource.scope.toc) namely table of contents, automatically, so you can use it in MDX document like:

<TableOfContentComponent toc={toc} />

Here is the explanation. You can have a try it.