Lets build a Markdown blog using Next.js, Shadcn, Tailwind, Pieces, Remark & Rehype 🔥

 Building a Markdown blog using **Next.js**, **Shadcn**, **Tailwind CSS**, **Pieces**, **Remark**, and **Rehype** is a fantastic idea! This stack will give you a modern, performant, and highly customizable blog. Let’s break it down step by step.


---


### **1. Set Up Next.js Project**

Start by creating a new Next.js project:


```bash

npx create-next-app@latest my-markdown-blog

cd my-markdown-blog

```


---


### **2. Install Tailwind CSS**

Install Tailwind CSS and configure it:


```bash

npm install -D tailwindcss postcss autoprefixer

npx tailwindcss init -p

```


Update `tailwind.config.js`:


```javascript

/** @type {import('tailwindcss').Config} */

module.exports = {

  content: [

    "./app/**/*.{js,ts,jsx,tsx}",

    "./pages/**/*.{js,ts,jsx,tsx}",

    "./components/**/*.{js,ts,jsx,tsx}",

  ],

  theme: {

    extend: {},

  },

  plugins: [],

};

```


Add Tailwind to your `globals.css`:


```css

@tailwind base;

@tailwind components;

@tailwind utilities;

```


---


### **3. Add Shadcn Components**

Shadcn is a collection of reusable components built on top of Tailwind CSS. Install it:


```bash

npx shadcn-ui@latest init

```


Follow the prompts to configure Shadcn. Then, add components as needed:


```bash

npx shadcn-ui@latest add button

npx shadcn-ui@latest add card

```


---


### **4. Set Up Markdown Processing**

To process Markdown files, we’ll use **Remark** and **Rehype**.


Install the required packages:


```bash

npm install remark remark-html remark-prism rehype-highlight gray-matter

```


- `remark`: Core Markdown processor.

- `remark-html`: Converts Markdown to HTML.

- `remark-prism`: Adds syntax highlighting with Prism.

- `rehype-highlight`: Alternative syntax highlighter.

- `gray-matter`: Parses front matter from Markdown files.


---


### **5. Create a Markdown Utility**

Create a utility function to parse Markdown files. Add a file `lib/markdownToHtml.js`:


```javascript

import { remark } from 'remark';

import html from 'remark-html';

import prism from 'remark-prism';

import matter from 'gray-matter';


export async function markdownToHtml(markdown) {

  const result = await remark()

    .use(html)

    .use(prism)

    .process(markdown);

  return result.toString();

}


export function parseMarkdown(content) {

  const { data, content: markdown } = matter(content);

  return { data, markdown };

}

```


---


### **6. Fetch and Display Markdown Posts**

Create a folder `_posts` in the root directory and add some Markdown files with front matter:


```markdown

---

title: "My First Post"

date: "2023-10-01"

---


# Hello, World!


This is my first blog post.

```


Create a page to list all posts (`pages/index.js`):


```javascript

import fs from 'fs';

import path from 'path';

import Link from 'next/link';

import { parseMarkdown } from '../lib/markdownToHtml';


export async function getStaticProps() {

  const postsDirectory = path.join(process.cwd(), '_posts');

  const filenames = fs.readdirSync(postsDirectory);


  const posts = filenames.map((filename) => {

    const filePath = path.join(postsDirectory, filename);

    const fileContent = fs.readFileSync(filePath, 'utf8');

    const { data } = parseMarkdown(fileContent);

    return {

      slug: filename.replace(/\.md$/, ''),

      ...data,

    };

  });


  return { props: { posts } };

}


export default function Home({ posts }) {

  return (

    <div className="container mx-auto p-4">

      <h1 className="text-3xl font-bold mb-4">Blog Posts</h1>

      <ul>

        {posts.map((post) => (

          <li key={post.slug} className="mb-2">

            <Link href={`/posts/${post.slug}`}>

              <a className="text-blue-500 hover:underline">{post.title}</a>

            </Link>

          </li>

        ))}

      </ul>

    </div>

  );

}

```


---


### **7. Create Dynamic Post Pages**

Create a dynamic route for individual posts (`pages/posts/[slug].js`):


```javascript

import fs from 'fs';

import path from 'path';

import { markdownToHtml, parseMarkdown } from '../../lib/markdownToHtml';


export async function getStaticPaths() {

  const postsDirectory = path.join(process.cwd(), '_posts');

  const filenames = fs.readdirSync(postsDirectory);


  const paths = filenames.map((filename) => ({

    params: { slug: filename.replace(/\.md$/, '') },

  }));


  return { paths, fallback: false };

}


export async function getStaticProps({ params }) {

  const filePath = path.join(process.cwd(), '_posts', `${params.slug}.md`);

  const fileContent = fs.readFileSync(filePath, 'utf8');

  const { data, markdown } = parseMarkdown(fileContent);

  const content = await markdownToHtml(markdown);


  return { props: { post: { ...data, content } } };

}


export default function Post({ post }) {

  return (

    <div className="container mx-auto p-4">

      <h1 className="text-3xl font-bold mb-4">{post.title}</h1>

      <div

        className="prose prose-lg"

        dangerouslySetInnerHTML={{ __html: post.content }}

      />

    </div>

  );

}

```


---


### **8. Add Syntax Highlighting**

To enable syntax highlighting, update your `tailwind.config.js`:


```javascript

module.exports = {

  content: [

    // ...existing content

  ],

  theme: {

    extend: {},

  },

  plugins: [require('@tailwindcss/typography')],

};

```


Then, wrap your Markdown content with the `prose` class (as shown in the `Post` component above).


---


### **9. Add Pieces for Code Snippets**

If you want to integrate **Pieces** for managing code snippets, you can use their API or SDK. Install the Pieces client:


```bash

npm install @pieces-app/client

```


Use it to fetch and display code snippets in your blog posts.


---


### **10. Deploy**

Deploy your blog to **Vercel** or any other platform:


```bash

vercel

```


---


### **Final Notes**

- Customize the design using Tailwind and Shadcn components.

- Add more features like tags, categories, or a search bar.

- Optimize performance with Next.js features like `getStaticProps` and `getStaticPaths`.


Let me know if you need help with any specific part! 🚀

Comments

Popular posts from this blog

How To Make Working Email Subscription Form With Google Sheets Using HTML CSS & JavaScript

Create Modern Landing Page with HTML CSS JS | Shery.js