-
-
Notifications
You must be signed in to change notification settings - Fork 216
Description
What problem does this feature solve?
@rspress/plugin-llms can currently output .md files, but when the source file is .mdx and includes custom components, only the file extension is changed — the components themselves remain as JSX.
As a result, the generated Markdown is not usable as plain Markdown content, especially for downstream LLM or text-processing tools.
I would like a way to transform MDX components into Markdown strings during the export process.
What does the proposed API look like?
I am considering two possible approaches:
Option 1: Export a toMarkdown function from component files
Each component file can export a toMarkdown function.
@rspress/plugin-llms detects and invokes this function to convert the component to Markdown.
Example: Component file with toMarkdown
// components/Note.tsx
import type { ReactNode } from 'react';
export type NoteProps = {
children: ReactNode;
};
export function Note(props: NoteProps) {
return <div className="note">{props.children}</div>;
}
// Used by @rspress/plugin-llms when converting MDX → MD
export function toMarkdown(props: NoteProps): string {
// A simple example: render as a blockquote in Markdown
return `> ${String(props.children).trim()}\n`;
}This does not work well when a single file contains multiple components, as only one toMarkdown can be exported.
Option 2: Define a custom component type that includes toMarkdown
Rspress could provide a component interface/type that allows defining toMarkdown on each component.
@rspress/plugin-llms would call toMarkdown for each used component during MDX → MD conversion.
Example: Component type with toMarkdown on the component itself
// `@rspress/core`
import type { FC } from 'react';
export interface RspressComponent<P = {}> extends FC<P> {
toMarkdown?: (props: P) => string;
}
export type RC<P = {}> = RspressComponent<P>;import type { RC } from '@rspress/core';
import type { ReactNode } from 'react';
export type NoteProps = {
children: ReactNode;
};
export const Note: RC<NoteProps> = (props) => {
return <div className="note">{props.children}</div>;
};
Note.toMarkdown = (props) => {
return `> ${String(props.children).trim()}\n`;
};This avoids the limitations of option 1 because each component can define its own toMarkdown method, even when multiple components are defined in the same file.
However, it requires Rspress to introduce (and document) a custom component type or convention for MDX components.
Option 3: Configure component → function mappings in @rspress/plugin-llms
Add an option to @rspress/plugin-llms that accepts a mapping from component names to functions used for MDX → MD conversion.
The plugin would look up the component name in this map and call the corresponding function at build time.
This keeps component definitions and Markdown conversion logic separate, and does not require a special component type.
Example: Configure mappings in Rspress config
// rspress.config.ts
import { defineConfig } from '@rspress/core';
import { pluginLlms } from '@rspress/plugin-llms';
export default defineConfig({
plugins: [
pluginLlms({
componentToMarkdown: {
// key = MDX component name
Note: (props: NoteProps) => {
return `> ${String(props.children).trim()}\n`;
},
},
}),
],
});Because the plugin API only receives component names and transformer functions from configuration, it is harder to keep this type-safe.
The mapping between component props and the transformer function is maintained manually, and there is no built-in guarantee that the props type used in the transformer matches the actual component’s props, especially across refactors.