in

Creating Your First Nuxt App: A Step-by-Step Guide to Building a CRUD Book Store

Nuxt.js is a progressive framework built on top of Vue.js that makes it easy to create universal or single page Vue applications. With its server-side rendering capabilities, automatic code splitting, simple routing system and other optimized features, Nuxt helps you build extremely fast and SEO-friendly web apps.

In this comprehensive guide, you‘ll learn how to create a Nuxt app from scratch by building a book store with full CRUD (Create, Read, Update, Delete) functionality.

Why Use Nuxt for Your Next Vue Project?

Before we dive into building the app, let‘s first go over some of the key benefits of using Nuxt:

  • Server-Side Rendering (SSR) – Nuxt automatically generates server-rendered app pages, boosting performance and SEO. No more waiting for JS to load before seeing page content.

  • File-based Routing – Routes are defined simply by creating .vue files and directories in the pages folder. Clean URLs with no configuration required.

  • Code Splitting – Nuxt will automatically split your app code into separate bundles so each page only loads what is needed for that route. Speeds up page loads.

  • Vuex Store – Nuxt includes Vuex out of the box. Manage app state easily with no setup needed.

  • Static Site Generation – In addition to SSR, Nuxt can pre-render all routes to static HTML for ultra-fast performance.

For large Vue apps where performance and SEO are critical, Nuxt makes things much easier compared to a traditional SPA. Now let‘s see how it works in practice!

Project Overview & Goals

Our goal is to build an app that displays a list of books, separated into three categories: "Recently Read", "Favorites" and "Best of the Best".

Users should be able to:

  • View all books
  • Add a new book
  • Edit book details
  • Delete a book
  • View an individual book details page

It will have a simple layout with three columns, one for each book category.

We won‘t use a database – instead, book data will be stored in the Vuex store. This keeps things simple as our focus is on learning Nuxt, not databases.

Scaffolding the Nuxt App

Let‘s begin by scaffolding out the basic Nuxt app structure using the create-nuxt-app CLI tool:

npx create-nuxt-app nuxt-bookstore

We‘ll select these options:

  • Package manager: Npm
  • UI framework: Vuetify
  • Nuxt modules: Axios
  • Linting tools: ESLint, Prettier
  • Testing framework: None
  • Rendering mode: Universal (SSR)

This will generate the boilerplate Nuxt app code with all our chosen libraries integrated.

The main folders and files generated are:

  • pages – View components go here and get automatically mapped as routes
  • layouts – App layouts
  • store – Vuex store
  • components – Reusable components

Let‘s now install our dependencies and start the dev server:

cd nuxt-bookstore
npm install
npm run dev

Our basic Nuxt app should now be running at http://localhost:3000.

Creating the Book Components

We‘ll start by creating two reusable components:

  • BookCard – display book info in a card
  • BookModal – form to add/edit books

Inside components/, create BookCard.vue:

<!-- BookCard.vue -->

<template>
  <v-card class="mx-auto" max-width="400">
    <v-img src="https://cdn.vuetifyjs.com/images/cards/sunshine.jpg" height="200px"></v-img>

    <v-card-title>{{title}}</v-card-title>

    <v-card-text>{{description}}</v-card-text>

    <v-card-actions>
      <v-spacer></v-spacer>

      <slot name="buttons"> </slot>
    </v-card-actions>
  </v-card>  
</template>

<script>
export default {
  props: [‘title‘, ‘description‘]
}
</script>

This displays a card with book title, description, and slots for buttons.

Next, create the modal in BookModal.vue:

<!-- BookModal.vue -->

<template>
  <v-dialog v-model="show" max-width="500">
    <v-card class="pa-5">
      <v-form @submit.prevent="submitForm">

        <v-text-field v-model="title" label="Title">
        </v-text-field>

        <v-textarea v-model="description" label="Description"></v-textarea>

        <v-btn type="submit">
          {{ isEditing ? ‘Update‘ : ‘Add‘ }} Book
        </v-btn>
      </v-form>
    </v-card>
  </v-dialog>
</template>

<script>
export default {
  data() {
    return {
      show: false,
      isEditing: false,

      title: ‘‘,
      description: ‘‘ 
    }
  },

  methods: {
    submitForm() {
      // Submit book
    }
  }
}
</script>

This provides a modal form to add/edit a book.

We‘ll integrate these components into the app next.

Setting Up the Books Page

Inside pages/index.vue, let‘s build out the books page:

<template>
  <v-container>
    <!-- Recently read books -->
    <h2 class="mb-5">Recently Read</h2>

    <div v-for="book in recentBooks">
      <BookCard :title="book.title" :description="book.description">

        <template v-slot:buttons>
          <v-btn @click="editBook(book)">
            Edit
          </v-btn>

          <v-btn @click="deleteBook(book)">
            Delete 
          </v-btn>
        </template>
      </BookCard>
    </div>

    <!-- Favorites -->
    <h2 class="mb-5">Favorites</h2>

    <div v-for="book in favoriteBooks">
      <BookCard :title="book.title" :description="book.description">

        <template v-slot:buttons>
          <v-btn @click="editBook(book)">
            Edit
          </v-btn>

          <v-btn @click="deleteBook(book)">
            Delete 
          </v-btn>
        </template>
      </BookCard>
    </div>

    <!-- Best books -->
    <h2 class="mb-5">Best Books</h2>

    <div v-for="book in bestBooks">
       <BookCard :title="book.title" :description="book.description">

        <template v-slot:buttons>
           <v-btn @click="editBook(book)">
            Edit
          </v-btn>

          <v-btn @click="deleteBook(book)">
            Delete  
          </v-btn>
        </template>
      </BookCard>
    </div>

    <v-btn @click="showAddBook">
      Add Book
    </v-btn>

    <BookModal ref="bookModal" />

  </v-container>
</template>

<script>
import BookCard from ‘@/components/BookCard.vue‘
import BookModal from ‘@/components/BookModal.vue‘

export default {
  components: {
    BookCard,
    BookModal
  },

  data() {
    return {
      recentBooks: [],
      favoriteBooks: [],
      bestBooks: []
    }
  },

  methods: {
    showAddBook() {
      this.$refs.bookModal.showModal()  
    },

    editBook(book) {
      // Open book modal in edit mode
    },

    deleteBook(book) {
      // Remove book 
    }
  }
} 
</script>

This displays the three book categories, with the BookCard component inside v-for loops to render each book.

BookModal is referenced so we can open the modal to add/edit books.

Next we need to add books to the store and populate these categories.

Connecting to the Vuex Store

Nuxt automatically adds Vuex to our app. Let‘s use it to manage book data.

Under store/, create an index.js file:

export const state = () => ({
  recentBooks: [
    { 
      title: ‘Book 1‘,
      description: ‘Description 1‘
    },
    {
      title: ‘Book 2‘,
      description: ‘Description 2‘  
    }
  ],

  favoriteBooks: [
    {
      title: ‘Favorite Book 1‘,
      description: ‘Favorite description 1‘
    }
  ],

  bestBooks: [
    {
      title: ‘Best Book‘,
      description: ‘Best description‘
    }
  ]  
})

This adds some initial book data to the store‘s state.

Now in pages/index.vue, we can import the state and populate our components:

<script>
import { state } from ‘@/store‘

export default {
  computed: {
    recentBooks() {
      return state.recentBooks
    },
    favoriteBooks() {
      return state.favoriteBooks
    },
    bestBooks() {
      return state.bestBooks
    }
  }
}
</script>

The books should now display on the page!

Implementing Book CRUD Functionality

Let‘s make the app interactive by enabling users to:

  • Add books
  • Edit books
  • Delete books

Inside the modal component, we need to handle form submission:

methods: {
  submitForm() {
    if (this.isEditing) {
      // Update book
    } else {  
      // Add new book 
    }

    this.show = false
  }
}

On submit, we will either edit an existing book or add a new one, depending on the mode.

To update the store, we‘ll create a book.js module:

// store/book.js

export const mutations = {
  addBook(state, book) {
    state.recentBooks.push(book)
  },

  editBook(state, updatedBook) {
    const book = state.recentBooks.find(b => b.title == updatedBook.title)

    Object.assign(book, updatedBook)
  },

  deleteBook(state, book) {
    state.recentBooks = state.recentBooks.filter(b => b.title !== book.title)
  }
}

This provides mutations to add, edit and delete books from the store state.

Now we can commit these mutations from our components:

// Inside modal submit handler
this.$store.commit(‘book/addBook‘, {
  title: this.title,
  description: this.description
})

// Inside page edit handler
this.$store.commit(‘book/editBook‘, book) 

// Inside page delete handler  
this.$store.commit(‘book/deleteBook‘, book)

Our book CRUD functionality is complete!

Creating Individual Book Pages

To view the details of a specific book, we can use Nuxt‘s file-based routing to generate dynamic pages.

First, create a _slug folder inside pages/. This tells Nuxt that any pages inside pages/_slug/ should be dynamic routes.

Then add an index.vue:

<template>
  <div>


    <p>{{ book.description }}</p>
  </div>
</template>

<script>
export default {
  async asyncData({ params }) {
    // Fetch book data using params.slug 
  }
}
</script>

Now when a user visits /books/some-book, this component will be rendered with that book data.

We can link to these pages from our BookCard:

<template v-slot:buttons>

  <nuxt-link :to="‘/books/‘ + book.title">
    View Book  
  </nuxt-link>

</template>

Nuxt will automatically generate these dynamic routes!

Deploying a Nuxt App

To deploy, run npm run generate. This will build the app and generate all routes as static HTML.

Simply host the dist/ folder on any static hosting service like Netlify.

For dynamic apps, use npm run build and host the output on a Node server.

And that‘s it! We‘ve built a fully-functional book management Nuxt app with:

  • A Vuex store
  • Reusable components
  • Dynamic pages and routes
  • Forms
  • CRUD functionality

Nuxt dramatically simplifies creating universal Vue apps.

Some next steps to improve this project could be:

  • Adding actual book data from an API
  • Implementing authentication
  • Improving styling and UI

I hope this gives you a solid foundation for building your own Nuxt projects! Let me know if you have any other questions.

AlexisKestler

Written by Alexis Kestler

A female web designer and programmer - Now is a 36-year IT professional with over 15 years of experience living in NorCal. I enjoy keeping my feet wet in the world of technology through reading, working, and researching topics that pique my interest.