An alternative way of loading content in Astro

Chris Bongers - Mar 16 '22 - - Dev Community

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');
Enter fullscreen mode Exit fullscreen mode

Which will return an object like this:

[
  {
    // Fronmatter parts for example:
    "title": "The title",
    "date": "2022-02-22",
    "astro": {
      "headers": [],
      "source": "",
      "html": ""
    },
    "url": ""
  }
]
Enter fullscreen mode Exit fullscreen mode

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.

The downside and a solution

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');
Enter fullscreen mode Exit fullscreen mode

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],
];
Enter fullscreen mode Exit fullscreen mode

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
  })
);
Enter fullscreen mode Exit fullscreen mode

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', '/');
  })
);
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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 };
    });
  })
);
Enter fullscreen mode Exit fullscreen mode

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, and let's connect!

Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on Facebook or Twitter

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player