Rendering External Markdown in Astro
Tags: astro, markdown, external
Published: 2024-02-07 14:30:34

It seems like I'm always writing the same article... 😂

I enjoy Astro, it's a good framework, but there is one thing about it or rather the docs that irks me.

Astro is pitched as a content first framework with native markdown support. That's what they say. However, this isn't *completely* the case.

When it comes to markdown that is local to your project, Astro does absolute wonders with the rendering and parsing. Your problems arise when you have your markdown from an external source i.e. a CMS. The docs have been structured in such a way that they want you to use local markdown and Content Collections.

But sometimes, your markdown is somewhere else. What is one to do then?

Let's go on a journey shall we? ...

## The Scenario

You use Hygraph as your CMS for your articles. You write your articles in markdown, and you can fetch them and all their data. What you want to do is have your articles rendered on your newly created Astro site.

The requirements for this task are as follows:
- It needs to be **one** thing - a package or whatever - that you import and use.
- You don't want to have to configure any additional things.

Before I give you the solutions that I think are best, I challenge you to find the solution within the Astro docs. I'll wait...

---

## The Solution(s)

### Markdown Component (deprecated)
I fought with this a while back when Astro was still in v1, and in those times, there was a package called `@astrojs/markdown-components`. That package has long since been deprecated, as such you won't be able to install it.   



For reference, this is how that would look (those who read my [Displaying Dev.to Post on Your Astro Site](https://dantedecodes.vercel.app/articles/how-to-display-devto-posts-on-an-astro-site-3icm)  article will be familiar with this code.)

```html
<!-- /articles/[slug].astro -->
---
import Markdown from "@astrojs/markdown-component";

export async function getStaticPaths() {
  const articles = await fetchArticles();

  return articles.map((article) => {
    return {
      params: { slug: article.slug },
      props: { article },
    };
  });
}

const {article} = Astro.props;
const {body_markdown}  = article;
---

<div>
	<Markdown content={body_markdown} />
</div>

```


A wise man once said, "If it ain't broke, don't fix it." 

My site has been working well with this package, and because of that, I will not upgrade it to a higher version as I am not in the mood to do the dance again.

> ##### Now, let's head on to the stuff that works with newer versions of Astro.

---

### Astro Pub

Repository: https://github.com/astro-community/md

#### Installation & Usage
```shell
npm install @astropub/md
```

```html
<!-- /articles/[slug].astro -->
---
import Markdown from "@astrojs/markdown-component";

export async function getStaticPaths() {
    ...
}

const {article} = Astro.props;
const {body_markdown}  = article;
---

<div>
  <Markdown of={body_markdown} />
</div>
```

> **NOTE**: Currently as of writing this, AstroPub requires  `astro@^3.0.0` to work smoothly.  

#### Thoughts
If I had no choice, but to fight this battle again, this is the method I would choose.

---

### Markdown-it

Repository: https://github.com/markdown-it/markdown-it

#### Installation & Usage

```shell
npm install markdown-it
```

```html
<!-- /articles/[slug].astro -->
---
import markdownit from "markdown-it";
const md = markdownit();

export async function getStaticPaths() {
 ...
}

const {content_markdown} = Astro.props
---

<div>
    <Fragment set:html={md.render(content_markdown)} />
</div>

```

> **NOTE**: Markdown-it also requires `astro ^3.0.0`

#### Thoughts
I don't like this method. I don't like it because:
- I have to declare a variable to store markdown-it.
- I have to use the `set:html` to render the content.
- I have to additionally call the render function and then pass my content to it.

---

### Astro Remote

> **Update: 29 February 2024**  
> After submitting an issue, Nate added the install command.

Repository: https://github.com/natemoo-re/astro-remote

#### Installation & Usage

```shell
npm install astro-remote
```

```html
<!-- /articles/[slug].astro -->
---
import {Markdown} from "astro-remote";

export async function getStaticPaths() {
 ...
}

const {content_markdown} = Astro.props
---

<div>
    <Markdown content={body_markdown} />
</div>

```

#### Thoughts
Astro Remote works very similarly to Astro Pub, and I like that about it.

---

### The Thing About Marked
If you did accept my challenge and looked in the docs, you might have found this section:

[Fetching Remote Markdown](https://docs.astro.build/en/guides/markdown-content/#fetching-remote-markdown)

The Astro docs recommend **marked**, but there's some things you have to be aware of with marked. 

Marked Site: https://marked.js.org/

#### Thoughts
Marked informs you on their site that it does not sanitise your markup. Do with that information what you will.

---
## Wrapping Up
Astro -  a brilliant little thing. A bit more care with regard to this part of their framework/documentation would be cool. At least as much care as is given to other parts of the docs.

On a steam, [whitep4nth3r](https://twitter.com/whitep4nth3r) went on a journey of trying to find this information on stream, her goal was to use things the 'Astro way. In the end, she went with the markdown-it approach.

The stream if you are curious. It's at 3hrs 57 minutes: https://www.twitch.tv/videos/1998429304?filter=archives&sort=time


---

### Thank you for reading, let's connect!

Thank you for visiting this little corner of mine. Let's connect on [Twitter](https://twitter.com/Psypher1), [Discord](https://discord.com/users/Pharaoh#5441/) and [LinkedIn](https://www.linkedin.com/in/jamesmidzi/)