Building a Full-Stack Application with Nuxt 3 and Vite
In this tutorial, we will build a full-stack application using Nuxt 3 and Vite. Nuxt 3 is a powerful framework for building server-side rendered Vue.js applications, while Vite is a fast build tool that leverages native ES modules. Combining these two technologies allows for efficient development and optimized production builds. This tutorial will guide you through setting up a Nuxt 3 project with Vite, creating a basic application structure, and implementing a simple feature.
Prerequisites
Before we begin, ensure you have the following installed on your system:
- Node.js (version 16 or later)
- npm (version 7 or later)
To verify if Node.js and npm are installed, run the following commands:
node -v
npm -v
If they are not installed, you can download and install them from the official Node.js website.
Project Structure
Once we set up our Nuxt 3 project, it will have the following structure:
nuxt3-vite-app/
├── node_modules/
├── pages/
│ └── index.vue
├── public/
├── nuxt.config.ts
├── package.json
└── tsconfig.json
Step 1: Setting Up a New Nuxt 3 Project
First, we'll create a new Nuxt 3 project using the official Nuxt CLI. Open your terminal and run the following command:
npx nuxi init nuxt3-vite-app
This command initializes a new Nuxt 3 project in a directory named nuxt3-vite-app. Once the setup is complete, navigate into the project directory:
cd nuxt3-vite-app
Next, install the project dependencies:
npm install
Explanation
The npx nuxi init command is used to scaffold a new Nuxt 3 application. This sets up the necessary files and directories for a Nuxt project. After that, npm install installs all the required dependencies specified in the package.json file.
Step 2: Configuring Vite
Nuxt 3 uses Vite as its default bundler, so there's minimal configuration required. However, you can customize the Vite configuration if needed by modifying the nuxt.config.ts file.
Open nuxt.config.ts and ensure it looks like this:
import { defineNuxtConfig } from 'nuxt3'
export default defineNuxtConfig({
build: {
transpile: [],
},
vite: {
server: {
fs: {
allow: ['..']
}
}
}
})
Explanation
The nuxt.config.ts file is where you configure your Nuxt application. We added a basic Vite configuration to allow file system access when running the development server, which is helpful for local development.
Step 3: Creating a Basic Page
Now, let's create a basic page to display in our application. Nuxt uses the file-based routing system, so any .vue file inside the pages directory automatically becomes a route.
Create a new file called index.vue inside the pages directory with the following content:
<template>
<div>
<h1>Welcome to Nuxt 3 with Vite</h1>
<p>This is a simple full-stack application.</p>
</div>
</template>
<script setup>
// You can add your script logic here
</script>
<style scoped>
h1 {
color: #42b883;
}
</style>
Explanation
The index.vue file is the default route of our application. It contains a simple template with a heading and a paragraph. The <script setup> block is a new feature in Vue 3 that allows you to write component logic in a more concise way. The <style scoped> ensures that the styles are scoped to this component only.
To start the development server and view your application, run:
npm run dev
Visit http://localhost:3000 in your browser to see the application in action.
In the next part of this tutorial, we will expand the application by adding more features and functionality.
Step 4: Adding a Dynamic Route
Let's add a dynamic route to demonstrate how Nuxt handles dynamic pages. We'll create a page that displays user profiles based on a user ID.
Create a new directory users inside the pages directory, and then create a file named [id].vue inside the users directory:
<template>
<div>
<h2>User Profile</h2>
<p>User ID: {{ userId }}</p>
</div>
</template>
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
const userId = route.params.id
</script>
<style scoped>
h2 {
color: #35495e;
}
</style>
Explanation
The [id].vue file creates a dynamic route where id is a placeholder for any value. When you navigate to /users/123, the id parameter will be 123. We use the useRoute hook to access route parameters and display the user ID.
Step 5: Fetching Data from an API
To make the application more interactive, let's fetch user data from a public API. We'll use the onMounted lifecycle hook to fetch data when the component is mounted.
Modify the [id].vue file to include API fetching:
<template>
<div>
<h2>User Profile</h2>
<p v-if="user">Name: {{ user.name }}</p>
<p>User ID: {{ userId }}</p>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const userId = route.params.id
const user = ref(null)
onMounted(async () => {
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`)
user.value = await response.json()
})
</script>
<style scoped>
h2 {
color: #35495e;
}
</style>
Explanation
We use the onMounted lifecycle hook to perform an API request to jsonplaceholder.typicode.com, a free online REST API. The ref function is used to create a reactive reference for the user object, which updates when the data is fetched.
Complete Working Example
Here's the complete structure and content of the project files:
nuxt.config.ts
import { defineNuxtConfig } from 'nuxt3'
export default defineNuxtConfig({
build: {
transpile: [],
},
vite: {
server: {
fs: {
allow: ['..']
}
}
}
})
pages/index.vue
<template>
<div>
<h1>Welcome to Nuxt 3 with Vite</h1>
<p>This is a simple full-stack application.</p>
</div>
</template>
<script setup>
// You can add your script logic here
</script>
<style scoped>
h1 {
color: #42b883;
}
</style>
pages/users/[id].vue
<template>
<div>
<h2>User Profile</h2>
<p v-if="user">Name: {{ user.name }}</p>
<p>User ID: {{ userId }}</p>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const userId = route.params.id
const user = ref(null)
onMounted(async () => {
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`)
user.value = await response.json()
})
</script>
<style scoped>
h2 {
color: #35495e;
}
</style>
Common Errors and Fixes
-
Error:
Cannot find module 'nuxt3'Fix: Ensure that you have installed all dependencies by running
npm installin the project directory. -
Error:
Failed to fetchFix: Check your network connection and ensure that the API endpoint is correct and accessible.
-
Error:
Cannot read property 'id' of undefinedFix: Verify that the route parameter is correctly defined and accessed using
useRoute().params.id.
Conclusion
In this tutorial, we built a basic full-stack application using Nuxt 3 and Vite. We set up a project, created static and dynamic pages, and fetched data from an API. This setup provides a foundation for building more complex applications with server-side rendering and fast development builds.