Reputation: 1901
md import pipeline renders to html, mdx import pipeline renders to .js/.ts/.jsx... which allows to customize html tags with Astro components.
I would like to take advantage of the mdx power in .md files with Astro
tried to configure mdx integration in Astro but it is excluding .md extension unfortunately to allow default md rehype pipeline
My workaround of renaming all .md files to .mdx is very intrusive (changes files meta data) I would like to find a different approach
forking mdx integration is hard to maintain
I started a vite plugin that changes .md ids to add an x as .mdx, then I had to write my own loader, then it got too complex
astro-remote only takes some default components and does allow to replace any custom component
I would like to avoid
and rather
Any ideas of the finest approach to achieve this, it feels like this last step is missing to unleash Astro's power over Markdow !!!
astro remote : https://github.com/natemoo-re/astro-remote
using old or deprecated options such as the previous <Markdown />
tag, might be an option to explore but should not result in separate feature branch where most of new features have to be manually maintained.
programmatic component creation https://github.com/withastro/astro/blob/main/packages/astro/test/units/render/jsx.test.js#L33-L35
Upvotes: 12
Views: 2552
Reputation: 1901
So after a long search I answer my own question, this is indeed possible in an elegant way.
example, it is also possible to use extensions optionally, but let's keep it simple
import {fromMarkdown} from 'mdast-util-from-markdown'
const tree = fromMarkdown(content)
toHtml(toHast(node))
here's how the full custom rendering recursive component looks like
---
import Heading from '../nodes/Heading.astro';
import Image from '../nodes/image/Image.astro'
import Code from '../nodes/code/Code.astro'
import {toHast} from 'mdast-util-to-hast'
import {toHtml} from 'hast-util-to-html'
export interface Props {
node: object;
data: object;
}
const {node, data} = Astro.props;
const handled_types = ["root","heading","paragraph","image","code"]
const other_type = !handled_types.includes(node.type)
---
{(node.type == "root") &&
node.children.map((node)=>(
<Astro.self node={node} data={data} />
))
}
{(node.type == "paragraph") &&
<p>
{node.children.map((node)=>(
<Astro.self node={node} data={data}/>
))}
</p>
}
{(node.type == "heading") &&
<Heading node={node} headings={data.headings}/>
}
{(node.type == "image") &&
<Image node={node} filepath={data.path}/>
}
{(node.type == "code") &&
<Code node={node} filepath={data.path}/>
}
{other_type &&
<Fragment set:html={toHtml(toHast(node))}></Fragment>
}
I tried this on a template project and it is working great, this is an example usage e.g. from a dynmaic route file such as [...sid].astro
---
const {sid} = Astro.params;
import AstroMarkdown from '@/components/renderers/AstroMarkdown.astro'
const data_content = await load_json(`gen/documents/${sid}/content.json`)
const tree = await load_json(`gen/documents/${sid}/tree.json`)
---
<AstroMarkdown node={tree} data={data_content} />
mdast-util-from-markdown
https://github.com/MicroWebStacks/content-structureUpvotes: 2