Vue.js Nuxt.js Framework
Introduction
Nuxt.js is a higher-level framework built on top of Vue.js that aims to simplify the development of Vue applications by providing a structured and opinionated approach. It was inspired by Next.js (a React framework) and offers powerful features like server-side rendering (SSR), static site generation (SSG), automatic routing, and a modular architecture.
Whether you're building a small application or a large-scale project, Nuxt.js provides the tools and conventions to make your development process more efficient and your applications more performant.
Why Use Nuxt.js?
Before diving into the details, let's understand why you might want to use Nuxt.js instead of plain Vue.js:
- Server-Side Rendering (SSR): Improves SEO and initial load performance
- Automatic Routing: Creates routes based on your file structure
- Code Splitting: Automatically splits your code for better performance
- Static Site Generation: Build static websites with dynamic data
- Powerful Configuration: Simple configuration with
nuxt.config.js
- Module System: Extend functionality with a rich ecosystem of modules
- Developer Experience: Hot module replacement, error reporting, and more
Getting Started with Nuxt.js
Installation
Let's start by creating a new Nuxt.js project:
npx create-nuxt-app my-nuxt-app
This interactive command will ask you several questions to customize your project:
- Choose between JavaScript and TypeScript
- Select your UI framework (Tailwind CSS, Bootstrap, etc.)
- Choose testing frameworks
- Configure rendering mode (Universal or SPA)
Once completed, navigate to your project folder and start the development server:
cd my-nuxt-app
npm run dev
Your Nuxt.js application should now be running at http://localhost:3000
.
Project Structure
Nuxt.js uses a convention-over-configuration approach, with a specific folder structure:
my-nuxt-app/
├── assets/ # Uncompiled assets like LESS, SASS, or JavaScript
├── components/ # Vue components
├── layouts/ # Application layouts
├── middleware/ # Custom functions that run before rendering pages
├── pages/ # Application views and routes
├── plugins/ # JavaScript plugins to run before mounting the app
├── static/ # Static files that are served directly
├── store/ # Vuex store files (optional)
├── nuxt.config.js # Nuxt.js configuration file
└── package.json # Project dependencies and scripts
Key Features of Nuxt.js
Automatic Routing
One of Nuxt.js's most powerful features is its automatic routing system based on the file structure in the pages
directory.
For example, this file structure:
pages/
├── index.vue
├── about.vue
└── users/
├── index.vue
└── _id.vue
Will automatically generate these routes:
/
→pages/index.vue
/about
→pages/about.vue
/users
→pages/users/index.vue
/users/:id
→pages/users/_id.vue
(dynamic route)
Let's create a simple page:
<!-- pages/index.vue -->
<template>
<div>
<h1>Welcome to my Nuxt.js application!</h1>
<nuxt-link to="/about">About Page</nuxt-link>
</div>
</template>
<script>
export default {
name: 'IndexPage'
}
</script>
And another page with a dynamic parameter:
<!-- pages/users/_id.vue -->
<template>
<div>
<h1>User Profile</h1>
<p>User ID: {{ $route.params.id }}</p>
<nuxt-link to="/">Back to Home</nuxt-link>
</div>
</template>
<script>
export default {
validate({ params }) {
// Must be a number
return /^\d+$/.test(params.id)
}
}
</script>
Server-Side Rendering vs. Static Site Generation
Nuxt.js supports different rendering modes:
- Universal (SSR): Server-side rendering with client-side hydration
- SPA: Client-side rendering only
- Static (SSG): Pre-renders all pages as HTML files at build time
You can configure the rendering mode in your nuxt.config.js
file:
// nuxt.config.js
export default {
// Universal SSR (default)
ssr: true,
// Static Site Generation
target: 'static'
// For SPA mode, set ssr: false
}
Data Fetching with Nuxt.js
Nuxt.js provides special lifecycle hooks for data fetching:
- asyncData: Runs before component initialization, can access route parameters
- fetch: Similar to asyncData but doesn't set component data
Example using asyncData
:
<!-- pages/posts/_id.vue -->
<template>
<div>
<h1>{{ post.title }}</h1>
<p>{{ post.body }}</p>
</div>
</template>
<script>
export default {
async asyncData({ params, $axios }) {
// Fetch data from an API
const post = await $axios.$get(`https://jsonplaceholder.typicode.com/posts/${params.id}`)
return { post }
}
}
</script>
Example using fetch
(Nuxt 2.12+):
<template>
<div>
<h1>Latest Posts</h1>
<div v-if="$fetchState.pending">Loading...</div>
<div v-else-if="$fetchState.error">Error while fetching posts</div>
<ul v-else>
<li v-for="post in posts" :key="post.id">{{ post.title }}</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
posts: []
}
},
async fetch() {
this.posts = await this.$axios.$get('https://jsonplaceholder.typicode.com/posts')
}
}
</script>
Layouts
Nuxt.js allows you to define different layouts for your pages:
<!-- layouts/default.vue -->
<template>
<div>
<header>
<nav>
<nuxt-link to="/">Home</nuxt-link>
<nuxt-link to="/about">About</nuxt-link>
</nav>
</header>
<main>
<nuxt />
</main>
<footer>
<p>© {{ new Date().getFullYear() }} My Nuxt App</p>
</footer>
</div>
</template>
To use a custom layout:
<!-- pages/about.vue -->
<template>
<div>
<h1>About Page</h1>
<p>This page uses a custom layout!</p>
</div>
</template>
<script>
export default {
layout: 'custom' // References layouts/custom.vue
}
</script>
Real-World Example: Building a Blog
Let's create a simple blog with Nuxt.js to demonstrate its capabilities in a real-world scenario.
Step 1: Set Up the Project
First, let's set up our Nuxt.js project:
npx create-nuxt-app nuxt-blog
Choose the following options:
- JavaScript
- UI framework: Tailwind CSS
- Axios module for HTTP requests
- Content module for document-driven development
Step 2: Create Blog Post Content
We'll use the Nuxt Content module to manage our blog posts:
mkdir -p content/blog
Create a markdown file for a blog post:
// content/blog/first-post.md
---
title: Getting Started with Nuxt.js
description: Learn the basics of Nuxt.js framework
author: Jane Doe
date: 2023-08-15
---
# Getting Started with Nuxt.js
This is my first blog post using Nuxt.js and Nuxt Content.
## What is Nuxt.js?
Nuxt.js is a framework built on top of Vue.js...
Step 3: Create Blog List and Detail Pages
Create a page to list all blog posts:
<!-- pages/blog/index.vue -->
<template>
<div class="container mx-auto px-4 py-8">
<h1 class="text-3xl font-bold mb-8">Blog Posts</h1>
<div v-if="$fetchState.pending">Loading posts...</div>
<div v-else-if="$fetchState.error">Error fetching posts</div>
<div v-else>
<div v-for="post in posts" :key="post.slug" class="mb-6">
<h2 class="text-xl font-semibold">
<nuxt-link :to="`/blog/${post.slug}`" class="text-blue-600 hover:underline">
{{ post.title }}
</nuxt-link>
</h2>
<p class="text-gray-500">{{ formatDate(post.date) }} • {{ post.author }}</p>
<p>{{ post.description }}</p>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
posts: []
}
},
async fetch() {
this.posts = await this.$content('blog')
.only(['title', 'description', 'slug', 'author', 'date'])
.sortBy('date', 'desc')
.fetch()
},
methods: {
formatDate(date) {
return new Date(date).toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
})
}
}
}
</script>
Create a page to display a single blog post:
<!-- pages/blog/_slug.vue -->
<template>
<div class="container mx-auto px-4 py-8">
<article>
<h1 class="text-4xl font-bold mb-4">{{ post.title }}</h1>
<p class="text-gray-500 mb-6">{{ formatDate(post.date) }} • {{ post.author }}</p>
<nuxt-content :document="post" />
</article>
<div class="mt-8">
<nuxt-link to="/blog" class="text-blue-600 hover:underline">
← Back to all posts
</nuxt-link>
</div>
</div>
</template>
<script>
export default {
async asyncData({ $content, params, error }) {
try {
const post = await $content('blog', params.slug).fetch()
return { post }
} catch (e) {
error({ statusCode: 404, message: "Blog post not found" })
}
},
methods: {
formatDate(date) {
return new Date(date).toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
})
}
},
head() {
return {
title: this.post.title,
meta: [
{ hid: 'description', name: 'description', content: this.post.description }
]
}
}
}
</script>
<style>
.nuxt-content h2 {
font-weight: bold;
font-size: 1.5rem;
margin-top: 1.5rem;
margin-bottom: 1rem;
}
.nuxt-content p {
margin-bottom: 1rem;
}
</style>
Step 4: Add SEO Optimization
Update the nuxt.config.js
file for better SEO:
// nuxt.config.js
export default {
// Other configurations...
head: {
title: 'My Nuxt.js Blog',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: 'A blog built with Nuxt.js' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
]
},
// Generate dynamic routes at build time for static hosting
generate: {
async routes() {
const { $content } = require('@nuxt/content')
const posts = await $content('blog').only(['slug']).fetch()
return posts.map(post => `/blog/${post.slug}`)
}
}
}
Step 5: Deploy the Blog
Build the static version of the blog:
npm run generate
This will create a dist
folder with all the static files needed for deployment to platforms like Netlify, Vercel, or GitHub Pages.
Nuxt.js Ecosystem
Nuxt.js has a rich ecosystem of modules that extend its functionality:
- @nuxt/content: Document-driven content management system
- @nuxtjs/axios: Integration with Axios for HTTP requests
- @nuxtjs/auth: Authentication module
- @nuxtjs/pwa: Progressive Web App support
- @nuxtjs/i18n: Internationalization for your Nuxt.js project
To add a module to your Nuxt.js project:
// nuxt.config.js
export default {
modules: [
'@nuxtjs/axios',
'@nuxt/content',
'@nuxtjs/pwa'
]
}
Nuxt.js Architecture
The following diagram illustrates how Nuxt.js works under the hood:
Summary
Nuxt.js is a powerful framework that enhances Vue.js with features like server-side rendering, automatic routing, and a module system. It provides an opinionated structure that helps developers build well-organized applications while maintaining the flexibility that Vue.js offers.
Key takeaways from this guide:
- Nuxt.js simplifies routing with a file-based system
- It offers multiple rendering modes: SSR, SPA, and Static
- Data fetching is handled through
asyncData
andfetch
- The framework comes with built-in layouts and middleware
- Nuxt.js has a rich ecosystem of modules to extend functionality
Additional Resources
To continue learning about Nuxt.js:
Exercises
- Create a simple portfolio website using Nuxt.js and static site generation.
- Build a small e-commerce product listing with Nuxt.js and the Axios module to fetch products from an API.
- Implement authentication in a Nuxt.js application using the Auth module.
- Create a multilingual blog using the i18n module.
- Convert an existing Vue.js application to use Nuxt.js and explore the benefits.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)