UmiUmi Enjoyers
12 min read

Building a Modern Blog with Nuxt 3

Create a beautiful, performant, and SEO-friendly blog using Nuxt 3, TailwindCSS, and modern web development practices.

1
Project Setup and Configuration

Setting up a new Nuxt 3 project with essential dependencies

Lets start by creating a new Nuxt 3 project and configuring it with the necessary dependencies for building a modern blog.

npx nuxi init modern-blog
cd modern-blog

# Install dependencies
npm install @nuxtjs/tailwindcss @nuxtjs/color-mode
npm install @tailwindcss/typography

# Configure nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    '@nuxtjs/tailwindcss',
    '@nuxtjs/color-mode'
  ],
  colorMode: {
    classSuffix: ''
  }
})

2
Content Management with Nuxt Content

Implementing a Git-based content management system

Nuxt Content v2 provides a powerful Git-based CMS that allows you to write your blog posts in Markdown with front matter.

# Install Nuxt Content
npm install @nuxt/content

# Create your first blog post
# content/blog/hello-world.md
---
title: Hello World
description: My first blog post
date: 2024-03-10
---

# Hello World

Welcome to my blog!

3
Dynamic Routes and Pagination

Creating dynamic blog post routes with pagination

Set up dynamic routing for blog posts and implement pagination for the blog listing page.

// pages/blog/[...slug].vue
const { data: post } = await useAsyncData('post',
  () => queryContent('blog')
    .where({ slug: route.params.slug })
    .findOne()
)

// pages/blog/page/[page].vue
const page = computed(() => parseInt(route.params.page as string) || 1)
const { data: posts } = await useAsyncData('posts',
  () => queryContent('blog')
    .sort({ date: -1 })
    .skip((page.value - 1) * 10)
    .limit(10)
    .find()
)

4
SEO and Meta Tags

Optimizing your blog for search engines

Implement proper SEO meta tags and social sharing cards for your blog posts.

// composables/useBlogMeta.ts
export const useBlogMeta = (post) => {
  useHead({
    title: post.title,
    meta: [
      { name: 'description', content: post.description },
      { property: 'og:title', content: post.title },
      { property: 'og:description', content: post.description },
      { property: 'og:image', content: post.image },
      { name: 'twitter:card', content: 'summary_large_image' }
    ]
  })
}

5
Search and Categories

Adding search functionality and category filtering

Implement client-side search and category filtering for your blog posts.

// composables/useSearch.ts
export const useSearch = () => {
  const searchQuery = ref('')
  const selectedCategory = ref('all')
  
  const filteredPosts = computed(() => {
    let results = posts.value
    
    if (searchQuery.value) {
      results = results.filter(post => 
        post.title.toLowerCase().includes(searchQuery.value.toLowerCase()) ||
        post.description.toLowerCase().includes(searchQuery.value.toLowerCase())
      )
    }
    
    if (selectedCategory.value !== 'all') {
      results = results.filter(post => 
        post.category === selectedCategory.value
      )
    }
    
    return results
  })
  
  return {
    searchQuery,
    selectedCategory,
    filteredPosts
  }
}

6
Syntax Highlighting and MDX

Adding code syntax highlighting and MDX support

Enhance your blog posts with syntax highlighting for code blocks and MDX for interactive components.

// Install required packages
npm install @nuxt/content @nuxtjs/color-mode shiki

// nuxt.config.ts
export default defineNuxtConfig({
  content: {
    highlight: {
      theme: {
        default: 'github-light',
        dark: 'github-dark'
      }
    }
  }
})

7
Add Comments Section

Enable user engagement with a comments section.

Implement a comment system and social sharing buttons for your blog posts.

// components/Comments.vue
<script setup>
const { data: comments } = await useAsyncData('comments',
  () => $fetch('/api/comments/' + props.postId)
)

const addComment = async (content) => {
  await $fetch('/api/comments/' + props.postId, {
    method: 'POST',
    body: { content }
  })
  
  // Refresh comments
  await refresh()
}
<script>

8
RSS Feed and Sitemap

Generating RSS feed and sitemap

Add RSS feed and sitemap generation for better discoverability.

// nuxt.config.ts
import { SitemapStream, streamToPromise } from 'sitemap'
import { Readable } from 'stream'

export default defineNuxtConfig({
  hooks: {
    'build:done': async () => {
      const posts = await queryContent('blog').find()
      const stream = new SitemapStream({ hostname: 'https://yourblog.com' })
      
      posts.forEach(post => {
        stream.write({
          url: `/blog/${post.slug}`,
          lastmod: post.updatedAt
        })
      })
      
      stream.end()
      const sitemap = await streamToPromise(Readable.from(stream))
      await writeFile('public/sitemap.xml', sitemap)
    }
  }
})

9
Performance Optimization

Optimizing your Nuxt 3 application for maximum performance

Implement key performance optimizations to ensure your Nuxt 3 blog loads quickly and runs smoothly.

// nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    payloadExtraction: true,
    inlineSSRStyles: false
  },
  nitro: {
    prerender: {
      routes: ['/sitemap.xml', '/rss.xml'],
      crawlLinks: true
    },
    compressPublicAssets: true
  },
  image: {
    provider: 'ipx',
    presets: {
      blog: {
        modifiers: {
          format: 'webp',
          quality: 80,
          loading: 'lazy'
        }
      }
    }
  },
  app: {
    head: {
      htmlAttrs: { lang: 'en' },
      link: [
        { rel: 'preconnect', href: 'https://fonts.googleapis.com' },
        { rel: 'dns-prefetch', href: 'https://fonts.googleapis.com' }
      ]
    }
  }
})
AA

Anton Andresen

Full Stack Developer & Nuxt Enthusiast