Open AllanChain opened 3 months ago
My solution is writing a simple rehype
plugin to compile the HTML tree to an Astro JSX, as Astro guarantees its JSX syntax to be a superset of HTML. I use this plugin to inline <style>
and <script>
tags, escape <style>
CSS, and import all Astro components mentioned in the HTML tree. The output will be provided as Vite virtual files, so the Astro compiler can further handle them. The down side of this setting is, the whole Astro markdown pipeline is evaded (including content collections, which shouldn't be useful in your Issues pipeline)
Thanks @Yixuan-Wang for sharing another approach. The idea of dynamically importing components mentioned in Markdown sounds really cool.
It's rather simple, I just force all Astro components in Markdown to follow WebComponent <component is="...">
syntax (other properties on the tag are preserved and forwarded to the Astro component). I don't quite like MDX and try to make my Markdown adhere to CommonMark with attribute extension.
View Post on Blog
Over the course of building my blog, I have experimented different levels of custom Markdown rendering solutions. In this post, I will provide a concise introduction to each of these methods.
Let us consider the following example. Suppose you have the following Markdown document:
How might one achieve this result? (Sorry, no MDX here, we are talking about standard Markdown.)
Manipulate HTML via regular expressions
The simplest solution would be doing regular expression replacements based on HTML rendered by third-party tools. Since my blog is build on GitHub issues, we will just start with the HTML return by GitHub:
We need to extract
python
from the class and add adiv
with classcode-lang
. The code iswith the result being
The problem is, the regular expression replacements are not always straightforward, and may have some unexpected results. Moreover, if GitHub changes the way HTML is rendered, my regular expression may suddenly stop working.
To enable more customizations and avoid such breaking changes made by GitHub, I moved on to the next level of Markdown custom rendering.
Remark and rehype
Remark is a tool that transforms Markdown with plugins, and rehype is for HTML. Markdown will first be parsed to AST by remark, and rehype will transform it to HTML AST and render it as HTML.
A basic example rendering and highlighting a code block is shown below:
And the output HTML is
To achieve custom Markdown rendering, one can create simple plugins manipulating Markdown AST or HTML AST. In the following code, we visit all nodes in HTML AST (
hast
), and find all<code>
tags that is a child of a<pre>
tag. We then match the class name and add a.code-lang
child.And the resulting HTML is:
Manipulating the AST is much safer and more straightforward than plain regular expression replacements, and thus enabling further customizations.
One problem, though, is that it is limited to adding simple DOM elements. If the element grows more and more complicated and nested, or components from some frontend frameworks are needed, this approach will not work well.
I have always wanted to use an Astro component for my blog images, but I have no idea how to achieve this, until I discovered the final (?) level of Markdown custom rendering.
Direct rendering Markdown AST
We can remove rehype all together and just use remark to parse and transform Markdown AST. Then, Astro (or any of your favorite frontend framework) can do the job of rendering Markdown AST to HTML. The drawback is that the component should handle all node types, even if customization is only needed for a single node type.
In the following code example, I have removed irrelevant parts to be concise:
The total LOC is definitely increased a lot compared with the previous example using rehype plugins. However, the relevant part for inserting
.code-lang
is even more simple and intuitive. More importantly, I can have as much logic as I needed in the<Image>
component, such as downloading the image and extracting the dimensions, creating low quality image placeholders (LQIP), etc. Since it essentially turns the plain Markdown to components, you can leverage the full power of Astro. For more examples, you can check out the code of this blog.Conclusion
Three different approaches for Markdown customization are introduced. However, exactly which method to choose depends on the specific situation and needs. If all you need is a simple modification, the regular expression approach may suit you best. If more customizations are needed, you can consider the second and even the third approach.