Building my portfolio blog with Dev.to and Next.js

View on dev.to

Check out my website here: stevenborrie.com

Previously I had experimented with tools like nextra, however I was unhappy with the lack of simplicity, and the default themes.

Dev.to API

Turns out, the dev.to API is incredibly simple. You can give it a try:

I realised I can just put all my posts on dev.to, and use it as a CMS database for my website.

Building my blog in Next.js

All I wanted to create was 2 pages: a home page, and a blog post page. The home page would be at / and the blog page at /post/[slug]. On the home page, I wanted to show a list of links to all of my blog posts, and on the blog post page, I wanted to show the content based on the [slug] parameter in the URL.

After setting up my project using yarn create next-app selecting typescript and the new app router, I added the following code to the homepage in src/app/page.tsx:

import Link from "next/link";

export default async function Home() {
  const posts = await fetch("https://dev.to/api/articles?username=saborrie", {
    next: { revalidate: 10 },
  }).then((x) => x.json());

  return (
    <main>
      <h2>Posts</h2>
      {posts.map(({ slug, title, description }: any) => (
        <Link href={`/post/${slug}`} className="post-list-item">
          <h3>{title}</h3>
          <small>{description}</small>
        </Link>
      ))}
    </main>
  );
}
Enter fullscreen mode Exit fullscreen mode

The new app router supports server side fetching by making your page components an async function. By default, Next.js will cache the results of the fetch at build time. We can configure the fetch to rerun during server rendering by setting the revalidate setting - I've set it to revalidate every 10 seconds in the code above.

To create the blog post page at /post/[slug] I added the file src/app/post/[slug]/page.tsx. Using the following code I am able to write out the title, cover_image, url, and body_html from the dev.to API:

export default async function Post({ params }: any) {
  const post = await fetch(`https://dev.to/api/articles/francescoxx/${params.slug}`, {
    next: { revalidate: 10 },
  }).then((x) => x.json());

  return (
    <div className="post">
      <img title="cover image" className="cover-image" src={post.cover_image} />
      <main>
        <h1>{post.title}</h1>
        <small>
          <a href={post.url}>View on dev.to</a>
        </small>
        <div dangerouslySetInnerHTML={{ __html: String(post.body_html) }} />
      </main>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

This worked great, except that I needed to do some work to get syntax highlighting in the code snippets. As dev.to is open source you can just go get the scss file at https://github.com/forem/forem/blob/main/app/assets/stylesheets/components/syntax.scss. To import scss in Next.js you need to run yarn add sass. And that's it, it worked. I was then able to copy my existing css from my old nextra portfolio in and I was done.