Create A Blog With NuxtJS

In this comprehensive tutorial, we'll build a complete blog using NuxtJS, covering everything from initial setup to deployment.

Prerequisites

Before we begin, make sure you have:

  • Node.js (version 14 or higher)
  • npm or Yarn package manager
  • Basic knowledge of Vue.js and JavaScript
  • Text editor (VS Code recommended)

Step 1: Create NuxtJS Application

The easiest way to create a NuxtJS application is by using the create-nuxt-app package. This can be installed by using the command.

yarn create nuxt-app <project-name>

This will run through a few questions to get you setup such as UI Framework, TypeScript, linter, testing framework and even the continuous integration platform you'd like to use.

Once installed you can run your nuxt site by using the following.

cd <project-name>
yarn dev

The application is now running on http://localhost:3000.

To make sure that you can view a page, go to the pages directory and add a new file for posts.vue and add a <template></template>, this will allow you to navigate to http://localhost:3000/posts to see the new posts page.

Step 2: Install Content Package

Now we have NuxtJS installed and running locally we need to install a package that will allow us to create content for the blog.

NuxtJS has an official package nuxt/content that will allow you to fetch content inside a markdown file via an API and act as a Git based headless CMS.

Install NuxtJS Content

To install you can use the following command.

yarn add @nuxt/content

To add modules into NuxtJS you need to add a module into the nuxt.config.js file.

{
    "modules": ["@nuxt/content"],
    "content": {
        // Options
    }
}

Step 3: Create Content Structure

Now we can create a markdown file in the content folder to fetch and display. As we're creating a blog we might want to have different content types therefore create a articles folder to place your markdown files inside.

You can define metadata for your blog post by adding a YAML front matter block to the top of the file:

---
title: Your Blog Post Title
slug: your-blog-post-slug
category: web-development
tags: [nuxtjs, vue, javascript]
extension: md
createdAt: 2022-06-12
description: A brief description of your blog post
author: Your Name
---

Your blog post content goes here...

You can then fill out the blog post content using the standard markdown syntax.

Step 4: Create Default Layout

You can extend the main layout in NuxtJS by creating your own default layout, create a file in layouts/default.vue and it will be used for all your pages that you don't specify a layout.

The simplest layout you can use is by just including in the <nuxt /> tag, this is what nuxt will use to inject in the page component.

<template>
    <Nuxt />
</template>

For this blog we want to include a header and footer, we'll use the below file as the main template:

<template>
    <div>
        <header-bar></header-bar>

        <div class="w-full md:container mx-auto px-6">
            <Nuxt />
        </div>

        <footer-bar></footer-bar>
    </div>
</template>

Step 5: Create Blog Pages

Homepage (index.vue)

Create an engaging homepage that showcases your latest blog posts:

<template>
    <div>
        <section class="hero mb-12">
            <h1 class="text-4xl font-bold mb-4">Welcome to My Blog</h1>
            <p class="text-xl text-gray-600">
                Discover articles about web development, Vue.js, and more
            </p>
        </section>

        <section class="latest-posts">
            <h2 class="text-2xl font-bold mb-6">Latest Posts</h2>
            <div class="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
                <article-card
                    v-for="post in posts"
                    :key="post.slug"
                    :post="post"
                />
            </div>
        </section>
    </div>
</template>

<script>
export default {
    async asyncData({ $content }) {
        const posts = await $content("articles")
            .sortBy("createdAt", "desc")
            .limit(6)
            .fetch();

        return { posts };
    },
};
</script>

Blog List Page (blog/index.vue)

<template>
    <div>
        <h1 class="text-3xl font-bold mb-8">All Blog Posts</h1>

        <!-- Search and Filter -->
        <div class="mb-8">
            <input
                v-model="searchTerm"
                type="text"
                placeholder="Search posts..."
                class="w-full p-3 border rounded-lg"
            />
        </div>

        <!-- Posts Grid -->
        <div class="grid md:grid-cols-2 gap-6">
            <article-card
                v-for="post in filteredPosts"
                :key="post.slug"
                :post="post"
            />
        </div>
    </div>
</template>

<script>
export default {
    data() {
        return {
            searchTerm: "",
        };
    },

    async asyncData({ $content }) {
        const posts = await $content("articles")
            .sortBy("createdAt", "desc")
            .fetch();

        return { posts };
    },

    computed: {
        filteredPosts() {
            if (!this.searchTerm) return this.posts;

            return this.posts.filter(
                (post) =>
                    post.title
                        .toLowerCase()
                        .includes(this.searchTerm.toLowerCase()) ||
                    post.description
                        .toLowerCase()
                        .includes(this.searchTerm.toLowerCase())
            );
        },
    },
};
</script>

Step 6: SEO Optimization

Add proper meta tags and schema markup for better search engine optimization:

<script>
export default {
    head() {
        return {
            title: this.post.title,
            meta: [
                {
                    hid: "description",
                    name: "description",
                    content: this.post.description,
                },
                {
                    hid: "og:title",
                    property: "og:title",
                    content: this.post.title,
                },
                {
                    hid: "og:description",
                    property: "og:description",
                    content: this.post.description,
                },
                { hid: "og:type", property: "og:type", content: "article" },
                {
                    hid: "twitter:card",
                    name: "twitter:card",
                    content: "summary_large_image",
                },
            ],
            script: [
                {
                    type: "application/ld+json",
                    json: {
                        "@context": "https://schema.org",
                        "@type": "BlogPosting",
                        headline: this.post.title,
                        description: this.post.description,
                        author: {
                            "@type": "Person",
                            name: this.post.author,
                        },
                        datePublished: this.post.createdAt,
                    },
                },
            ],
        };
    },
};
</script>

Step 7: Performance Optimization

Image Optimization

Use the @nuxt/image module for automatic image optimization:

yarn add @nuxt/image

Add to nuxt.config.js:

modules: ["@nuxt/content", "@nuxt/image"];

Code Splitting

NuxtJS automatically handles code splitting, but you can optimize further:

// nuxt.config.js
export default {
    build: {
        optimization: {
            splitChunks: {
                chunks: "all",
                maxSize: 200000,
            },
        },
    },
};

Step 8: Deployment Options

Static Generation with Netlify

  1. Build your static site:
yarn generate
  1. Deploy the dist folder to Netlify, Vercel, or GitHub Pages.

Server-Side Rendering with Heroku

  1. Create a package.json build script:
{
    "scripts": {
        "heroku-postbuild": "npm run build"
    }
}
  1. Deploy to Heroku with automatic builds.

Frequently Asked Questions

How do I add a contact form to my NuxtJS blog?

You can add a contact form using the @nuxtjs/axios module to handle form submissions. Consider using services like Netlify Forms or Formspree for static sites.

Can I use a CMS with my NuxtJS blog?

Yes! You can integrate headless CMS solutions like:

  • Contentful
  • Strapi
  • Ghost
  • Forestry

How do I improve my blog's loading speed?

  1. Enable gzip compression
  2. Use the @nuxt/image module for image optimization
  3. Implement lazy loading for images
  4. Use a CDN for static assets
  5. Enable browser caching

How do I add analytics to my NuxtJS blog?

Install the @nuxtjs/google-analytics module:

yarn add @nuxtjs/google-analytics

See our guide on adding Google Analytics to Nuxt3 for detailed instructions.

Can I add a dark mode to my blog?

Yes! Use the @nuxtjs/color-mode module for easy dark mode implementation with automatic system preference detection.

Enhance your NuxtJS blog with these additional features:

Best Practices

  1. Content Organization: Use a clear folder structure for your content
  2. Image Optimization: Always compress and resize images appropriately
  3. SEO: Include proper meta tags and schema markup
  4. Performance: Regularly audit your site with Lighthouse
  5. Accessibility: Use semantic HTML and proper ARIA labels

Conclusion

You now have a complete, production-ready blog built with NuxtJS. This setup provides excellent performance, SEO capabilities, and developer experience. The modular architecture makes it easy to extend with additional features as your blog grows.

Remember to regularly update your dependencies and consider implementing a CI/CD pipeline for automated deployments.