A Step-By-Step Guide to Building Your Own Personal Blog
In this tutorial, which is split into two parts I'm going to walk you through the steps of building a full-stack blog website with Next.JS, React.JS, TypeScript, Sanity.io, and TailwindCSS for the styling
Prerequisites and Requirements
- Node.js installed on your device
- Basic to intermediate knowledge with JavaScript or TypeScript.
- Familiarity with React.JS and Next.JS.
- Basic to intermediate knowledge on CSS.
- Text editor, preferably V.S Code.
- Git installed on your machine, and having a GitHub account.
- An account on Vercel as a hoisting platform
Setting Up Sanity Studio
To add our blog posts we'll use Sanity, as follows:
- After logging-in into your Sanity account on your browser, go to the sanity project which you built earlier on your terminal.
- Navigate to settings --> API settings.
- Cd into your sanity project mine is: < batblog > and run the local sanity studio
Fetching From Sanity Studio
In sanity studio on your browser, you can see a button labeled vision in the navbar, where we'll be able to query for our posts' data after clicking "fetch", as such
So now all we have to do is query for the posts' data in the frontend to be able to get them rendered. And how to do that? Just follow these steps:
- Create sanity.js file inside your Next.JS app.
- Install a new package but first make sure you're cd'ing into Next.JS project on the terminal, not sanity project, and type in this command:COPYCOPY
```*[_type == 'post']{
_id,
title,
slug,
author -> {
name,
image,
}
}
``` - ```npm i next-sanity
``` - ```// Inside sanity.js
import { createCurrentUserHook, createClient } from "next-sanity";
import createImageUrlBuilder from "@sanity/image-url";
export const config = {
dataset: process.env.NEXT_PUBLIC_SANITY_DATASET || "production",
projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
apiVersion: "2021-03-25",
useCdn: process.env.NODE_ENV === "production",
};
// This is to fetch data by making a query to the backend in sanity studio
export const sanityClient = createClient(config);
// This will parse the source we get back from the query and give us the image url
export const urlFor = (source) => createImageUrlBuilder(config).image(source);
export const useCurrentUser = createCurrentUserHook(config);
```
```// Inside index.tsx at the very bottom
export const getServerSideProps = async () => {
const query = `*[_type == "post"] {
_id,
title,
author-> {
name,
image
},
description,
mainImage,
slug
}`;
const posts = await sanityClient.fetch(query);
// This is where we return the props
return{
props: {
posts,
}
}
}
```
```// Inside index.tsx
import Header from "../components/Header";
import Footer from "../components/Footer";
import { sanityClient, urlFor } from "../sanity";
export default function Home({ posts }: Props) {
return (
<div className="mx-auto max-w-7xl">
<Head>
<title>Batool Blog</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<Header />
<div className="flex items-center justify-between px-10 mx-auto space-y-5 bg-gray-300 rounded max-w-7xl sm:p-10">
<div className="">
<h1 className="max-w-xl font-sans text-5xl ">
<span className="font-serif cursor-pointer">BatoolBlog</span> is a
place where Batool writes!
</h1>
<h2 className="pt-5 font-sans text-2xl text-black">
Join in, you might be interested!{" "}
</h2>
</div>
<div className="items-center hidden md:inline-flex">
<img
className="h-auto rounded-lg w-96 "
src="https://images.unsplash.com/photo-1508780709619-79562169bc64?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80"
/>
</div>
</div>
</div>
);
}
```
```// Inside typings.d.ts
export interface Post{
_id: string;
_createdAt: string;
title: string;
author:{
name:string;
image: string;
},
description: string;
mainImage:{
asset:{
url:string;
};
};
slug:{
current: string;
};
body: [object];
}
```