An alternative way of loading content in Astro

I'm a full-stack developer from South Africa 🇿🇦. I love writing about JavaScript, HTML and CSS.
Search for a command to run...

I'm a full-stack developer from South Africa 🇿🇦. I love writing about JavaScript, HTML and CSS.
No comments yet. Be the first to comment.
Most of you know me for my consistency, a golden arrow in my blog series. I've written 1000 articles in 1008 days! Almost an article a day, and my honeymoon was the only holiday I ever took. I'm super proud of this achievement; it has been a fantasti...

It's not the first time I'll be talking about community. I think it's an essential aspect of any successful tool. This shows in my previous explorations of Astro, Medusa, and now Vendure as well. All these products thrive in a super open, welcoming, ...

The cool part about Vendure is how easy it is to set up and how abstract each layer is. Basically, we get the following elements: External database Server Worker Admin UI Frontend While this is amazing, it also brings a bit of complexity when it co...

The previous article looked at customizing Vendure on a data and process level. In this article, we'll look at customizing emails, as they are often a big part of a webshop system. We'll be looking at two different layers of customization for customi...

Even though Vendure is a pretty significant project out of the box, in some cases, we might want to go in and modify some elements to work to our specific use case. In this article, I'll take a high-level look at some elements we can customize within...

Astro has a super cool function called fetchContent it can be used to fetch content from your pages.
A little example, if I want to retrieve all my posts in Astro I simply use the following command:
const allPosts = Astro.fetchContent('../pages/posts/*.md');
Which will return an object like this:
[
{
// Fronmatter parts for example:
"title": "The title",
"date": "2022-02-22",
"astro": {
"headers": [],
"source": "",
"html": ""
},
"url": ""
}
]
As you can see, pretty slick way to retrieve all our content with all the data quickly.
And this method is perfect since it returns everything we need.
I wanted to render related posts on each article, which sounded like a great idea.
I started by using fetchContent, but quickly came across a downside to using this function.
It could cause infinite loops. This is because it technically renders the HTML, so if you refer to other posts (like recommended posts), it will cause an endless loop in your script.
The solution is to use Astro's underlying method, limiting the response.
Officially they used globEager, but I used glob from the start. Not sure what the difference is between the two at the time of writing.
To load all the posts as before we can use the following code:
const allPosts = await import.meta.glob('../pages/posts/*.md');
However, instead of an excellent formatted array, this will return promise based array like this:
[
'../pages/posts/are-you-participating-in-the-reply-code-challenge.md': [Function: ../pages/posts/are-you-participating-in-the-reply-code-challenge.md],
'../pages/posts/asking-questions.md': [Function: ../pages/posts/asking-questions.md],
];
The first part (the key) is the file name, and the value is lazy loaded import (powered by Vite).
If you need to access the front matter part of your posts, we'll have to loop over them, as until now, all we have is the filename.
I'm going to create another array called mappedPosts in which we'll loop over all the keys, which will look like this:
const mappedPosts = await Promise.all(
Object.keys(allPosts).map((key) => {
// Todo
})
);
Since this is a lazy promise, we need to retrieve the function and do wait for the return.
But first, I'll store the current post and convert the file name into a slug.
const mappedPosts = await Promise.all(
Object.keys(allPosts).map((key) => {
const post = allPosts[key];
const url = key.replace('../pages/', '/').replace('.md', '/');
})
);
We simply replace our prefix, and the extension, this will result in the following examples:
// ../pages/posts/why-tailwind-jit-compiler-is-amazing.md
// /posts/why-tailwind-jit-compiler-is-amazing
The last thing we want to do is return the promised result and format the necessary elements.
Remember from the intro, which elements are available? You can use any of those. I choose only to return the front matter part and the url.
const mappedPosts = await Promise.all(
Object.keys(allPosts).map((key) => {
const post = allPosts[key];
const url = key.replace('../pages/', '/').replace('.md', '/');
return post().then((p) => {
return { ...p.frontmatter, url };
});
})
);
And now we have a neat array of posts with frontmatter parts that don't cause an infinite loop.
You can now do all the filtering you want on this array.
This way is a bit more work, but it does make things more dynamic for you.
Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on Facebook or Twitter