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.
Project Overview
This is the general structure we should have after everything has completed.
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:
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:
https://dev.to/api/articles
- get all articles from the dev.to platformhttps://dev.to/api/articles/latest?username=psypher1
- which will return the latest articles by a user
For our needs we are going to be using this one
https://dev.to/api/api/articles/me/published
- that will get more specific. To use it however, we will need an API key.
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
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>
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:
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