How to Display Dev.to Posts on an Astro Site

How to Display Dev.to Posts on an Astro Site

Leveraging features of two technologies

While I was talking time off it gave me the opportunity to go back and have a look at things that have been on my back burner - be it technologies, books etc

History

My first introduction to Astro was through a Learn with Jason a while back...

Now that it's at v2, I am confident enough to do an article and walk-through about it.

What is Astro?

Astro is... is... is...

I want to say Static Site Generator, but since its inception in that video it does more than just SSG. I would say it is a Bring Your Own Framework framework.

Why? You don't need any prior knowledge of any framework to use Astro.

You only know HTML and CSS? You can use Astro right away. You have a framework you're particular on? Sure, Astro has you covered.

So today I thought I'd do a walkthrough of embedding your Dev.to posts into your Astro site

Let's begin shall we?

NOTE: I have done something along these lines with Hashnode posts and Eleventy. You can find that on my GIthub


Getting Started

Contrary to a lot of a lot of documentation sites, Astro's documentation is actually really good.

Eleventy, Next.js, I'm looking at you...

The Astro team has worked really hard to make sure that things are simple enough to understand regardless of your level.

We'll start by heading to the Astro docs and follow the installation guide starting with this command:

NOTE: You need to have Node installed for this next part.

npm create astro@latest

The nice thing about the Astro install process is that they guide you through each step. But so that we have the same working structure, after you give your project a name follow accept the following prompts:

  • Include sample files

  • install dependencies

  • initialise a git repository

We are however not using typescript.

astro cli

Project Overview

This is the general structure we should have after everything has completed.

astro project

The main folder we will be working from is the src one - that is where the bulk of our site exists.

We can run our project with the command in the terminal:

npm run dev

The server will be running on this port: http://127.0.0.1:3000/

We are going to make some changes before jumping into handling data. Open src/pages/index.astro and remove everything inside the Layout tags and we'll replace it with

src/pages/index.astro

<h1> Blog home </h1>

This is what you should now have:

home

Astro Page Structure

Astro file are divided into two main sections; the frontmatter and the rest of the file - the template.

---
const {title} = Astro.props
---

<section>
    <h1>{title}</h1>
</section>

The top frontmatter area exposes a top level fetch which we will be using to achieve some of our goals here.


Getting Astro Ready

For this part, we will need to consume the Dev.to API

Dev.to API

Dev.to has several APIs you can use to fetch articles. For example:

For our needs we are going to be using this one

Here are the Forem docs where I got these endpoints

API key

Had over to your Dev.to profile and generate your key. Go the settings of your DEV.to profile, then select Extensions.

From there scroll all the way to the bottom and you should see an option to generate a new key

devto key

With your key acquired, let's create a couple of environment variables. In the root of our Astro project, create a file named .env with this in it

DEV_TO_API_URL=https://dev.to/api/
DEV_API_KEY=

Next, we'll make a folder called lib in src and in it we'll make a getArticles.js file with this in in:

// src/lib/getArticles.js
const { DEV_API_KEY, DEV_TO_API_URL } = import.meta.env;

export async function fetchArticles() {
  const res = await fetch(DEV_TO_API_URL + "articles/me/published", {
    headers: {
      "api-key": DEV_API_KEY,
    },
  });
  const data = await res.json();
  const articles = data;

  return articles;
}

List Articles

Let's now list our articles on our home page

<!-- src/pages/index.astro-->

---
import Layout from "../layouts/Layout.astro";
import { fetchArticles } from "../lib/getArticles";

const articles = await fetchArticles()
---

<Layout title="Dev.to Astro">
    <h1>Blog Home</h1>

    <section>
        {
            articles.map((article) => (
                <article>
                    <h2>{article.title}</h2>
                    <p>{article.description}</p>
                    <a href={`blog/${article.slug}`}>read more</a>
                </article>
            ))
        }
    </section>
</Layout>

article list


Dynamic Pages

This part is the reason I chose to investigate this. I read how @nunogois wrote an article in how he embeds his Dev.to articles on his Svelte site.

I wanted to see if I could achieve the same on another one of my sites, but what to build it with? I've already done something similar with my Hashnode articles on my Eleventy site. Then I remembered Astro...

The Detail Page

First we'll make a folder and a file in pages blog/[slug].astro:

<!-- src/pages/blog/[slug].astro-->
---
import Layout from "../../layouts/Layout.astro";


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

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

  return paths;
}

const { slug } = Astro.params;
const { title, cover_image, published_at, body_markdown } = Astro.props;
---

<Layout title="">

</Layout>

If you've used Next.js the above part should be familiar to you.

Basically, we have to tell Astro which paths (slugs) we want to render using getStaticPaths

From getStaticPaths we return params and props objects which we will use to render our individual pages.

Using Astro.props we can then destructure the particular items we want rendered on the page.

Rendering the Markdown

The article content from Dev.to is in markdown format. Having it render properly is a bit tricky....

The Markdown component that allows us to render our article is no longer part of the Astro core and has to be installed.

Luckily for us, Astro hasn't discontinued support for the Markdown component. Let's install it:

npm i @astrojs/markdown-component

Our slug page should now look like this:

---
import Layout from "../../layouts/Layout.astro";

import { fetchArticles } from "../../lib/getArticles";

import Markdown from "@astrojs/markdown-component";

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

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

    return paths;
}

const { slug } = Astro.params;
const { title, cover_image, published_at, body_markdown } = Astro.props;
---

<Layout {title}>
    <h1>{title}</h1>
    <small>{new Date(published_at).toLocaleDateString("en-UK")}</small>

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

And here we go:

article detail

A Very Important Note

As you've noticed what we have done doesn't look very nice. This was done on purpose as my main focus was pulling the data and displaying it on our site.

Styling an Astro project is a whole entire topic on its own. If there is need for it I will gladly go over how I would style what we have done.

The repo that accompanies this article if anyone is interested https://github.com/Psypher1/astro-devto-walkthrough


Conclusion

Much like my Eleventy series, going back to the core of the web is really refreshing. Reenforcing those lessons is really fun for me. I learnt quite a lot whilst doing this, I hope you did too.

PS: My new site currently makes use of this implementation. Yes, I rebuilt it again.

Here it is Dante Decodes


Thank you for reading, let's connect!

Thank you for visiting this little corner of mine. Let's connect on Twitter, Polywork and LinkedIn