Building my portfolio blog with Dev.to and Next.js
Published: 2023-05-11 07:47:46

Check out my website here: [stevenborrie.com](https://stevenborrie.com)

Previously I had experimented with tools like [nextra](https://nextra.site/), 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: 

- JSON array of all my posts: [https://dev.to/api/articles?username=saborrie](https://dev.to/api/articles?username=saborrie)
- This post: [https://dev.to/api/articles/saborrie/building-my-portfolio-blog-with-devto-and-nextjs-268f](https://dev.to/api/articles/saborrie/building-my-portfolio-blog-with-devto-and-nextjs-268f)

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`:

```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>
  );
}
```

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:

```tsx
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>
  );
}
```

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](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.