📘 PHẦN 6: NUXT.JS NÂNG CAO - SERVER, AUTHENTICATION VÀ TRIỂN KHAI
🎯 Mục tiêu tổng quát
- Xây dựng các API endpoint của riêng mình ngay bên trong ứng dụng Nuxt.
- Sử dụng middleware để thực thi logic trước khi điều hướng đến một trang, ví dụ như kiểm tra quyền truy cập.
- Tích hợp một giải pháp xác thực người dùng hoàn chỉnh.
- Quản lý metadata của trang (title, description) để tối ưu hóa SEO.
- Triển khai thành công ứng dụng Nuxt lên một nền tảng hosting hiện đại.
🧑🏫 Bài 1: Xây dựng API với Server Routes
Thư mục server/
Nuxt cho phép bạn xây dựng một backend hoàn chỉnh ngay bên trong dự án của mình thông qua thư mục server/. Mọi file trong server/api/ sẽ tự động được ánh xạ thành một API endpoint.
Tạo API Endpoint
Tạo một file trong server/api/. Tên file sẽ quyết định URL.
Ví dụ: server/api/hello.js
// `defineEventHandler` là một hàm tiện ích của Nuxt
export default defineEventHandler((event) => {
// `event` chứa thông tin về request (headers, params, ...)
// Trả về dữ liệu JSON
return {
message: 'Chào bạn từ API của Nuxt!',
};
});Endpoint này sẽ có thể truy cập được tại http://localhost:3000/api/hello.
Ví dụ với tham số động: server/api/products/[id].js
export default defineEventHandler((event) => {
// Lấy `id` từ params
const productId = event.context.params.id;
// Giả lập việc lấy dữ liệu từ database
if (productId === '1') {
return { id: 1, name: 'Laptop Pro', price: 30000000 };
} else {
// Xử lý trường hợp không tìm thấy
throw createError({
statusCode: 404,
statusMessage: 'Sản phẩm không tồn tại',
});
}
});Gọi API từ phía client
Bạn có thể dùng useFetch để gọi chính các API bạn vừa tạo.
<script setup>
const { data, error } = await useFetch('/api/hello');
</script>
<template>
<p>{{ data?.message }}</p>
</template>🧑🏫 Bài 2: Middleware - Can thiệp vào quá trình điều hướng
Middleware là gì?
Là các đoạn code chạy trước khi người dùng được điều hướng đến một trang cụ thể. Chúng rất hữu ích để kiểm tra quyền, chuyển hướng, hoặc sửa đổi request.
Các loại Middleware trong Nuxt
- Inline Middleware: Định nghĩa trực tiếp trong trang sử dụng
definePageMeta. - Named Middleware: Định nghĩa trong thư mục
middleware/, có thể tái sử dụng ở nhiều trang. - Global Middleware: Đặt tên file có đuôi
.global.jstrongmiddleware/, sẽ tự động chạy trên mọi route.
Ví dụ: Middleware bảo vệ Route
Tạo file
middleware/auth.js:javascript// middleware/auth.js // `to` là route người dùng đang muốn đến // `from` là route người dùng đến từ export default defineNuxtRouteMiddleware((to, from) => { // Giả lập logic kiểm tra đăng nhập const isLoggedIn = false; // Thay bằng logic thật // Nếu người dùng chưa đăng nhập và đang cố vào trang dashboard if (!isLoggedIn && to.path === '/dashboard') { // Chuyển hướng về trang đăng nhập return navigateTo('/login'); } });Áp dụng vào trang:
vue<!-- pages/dashboard.vue --> <script setup> definePageMeta({ middleware: 'auth' // Hoặc nhiều middleware: middleware: ['auth', 'analytics'] }); </script>
🧑🏫 Bài 3: Giới thiệu về Authentication
Các phương pháp xác thực
Tương tự như trong hệ sinh thái React, các phương pháp phổ biến là Cookie-based, Token-based (JWT) và OAuth.
Giải pháp cho Nuxt: Sidebase/nuxt-auth
Đây là một module cộng đồng mạnh mẽ, lấy cảm hứng từ NextAuth.js, giúp việc tích hợp xác thực vào Nuxt trở nên dễ dàng. Website: https://sidebase.io/nuxt-auth/getting-started
Thiết lập cơ bản
Cài đặt:
npm install --save-dev @sidebase/nuxt-authCấu hình trong
nuxt.config.ts:typescriptexport default defineNuxtConfig({ modules: ['@sidebase/nuxt-auth'], auth: { // Cấu hình các provider (ví dụ: GitHub) } })Tạo API route để xử lý:
server/api/auth/[...].tsĐây là nơinuxt-authsẽ xử lý các request đăng nhập, đăng xuất, lấy session...
Sử dụng session trong component
Module này cung cấp composable useAuth để bạn có thể lấy thông tin người dùng.
<script setup>
const { status, data: session, signIn, signOut } = useAuth();
// status: 'authenticated', 'unauthenticated', 'loading'
// session: chứa thông tin người dùng
</script>
<template>
<div>
<div v-if="status === 'authenticated'">
<p>Xin chào, {{ session.user.name }}</p>
<button @click="signOut()">Đăng xuất</button>
</div>
<div v-else>
<p>Bạn chưa đăng nhập.</p>
<button @click="signIn('github')">Đăng nhập với GitHub</button>
</div>
</div>
</template>🧑🏫 Bài 4: Tối ưu hóa SEO và Metadata
Tại sao SEO quan trọng?
Nuxt render trên server, giúp các công cụ tìm kiếm (Google, Bing) có thể đọc nội dung trang của bạn một cách dễ dàng, cải thiện thứ hạng tìm kiếm. Để làm điều này hiệu quả, bạn cần cung cấp metadata (dữ liệu mô tả) cho mỗi trang.
Sử dụng useHead
Nuxt cung cấp composable useHead để bạn có thể quản lý các thẻ trong <head> của trang (như title, meta).
<!-- pages/about.vue -->
<script setup>
useHead({
title: 'Giới thiệu | SimpleStore',
meta: [
{ name: 'description', content: 'Tìm hiểu về cửa hàng của chúng tôi.' }
]
})
</script>Tạo metadata động
Bạn có thể kết hợp useFetch và useHead để tạo title và description động cho các trang chi tiết.
<!-- pages/products/[id].vue -->
<script setup>
const route = useRoute();
const { data: product } = await useFetch(`/api/products/${route.params.id}`);
// Cập nhật <head> với dữ liệu từ sản phẩm
if (product.value) {
useHead({
title: `${product.value.name} | SimpleStore`,
meta: [
{ name: 'description', content: product.value.description }
]
});
}
</script>🧑🏫 Bài 5: Triển khai ứng dụng (Deployment)
Các lựa chọn Hosting
Nuxt có thể được triển khai trên nhiều nền tảng:
- Vercel: Hỗ trợ tốt nhất, tích hợp hoàn hảo.
- Netlify: Một lựa chọn phổ biến khác.
- Cloudflare Pages, Render, Heroku...
- Tự host trên server riêng (Node.js).
Triển khai lên Vercel
Quy trình tương tự Next.js:
- Push code lên GitHub.
- Đăng ký tài khoản Vercel và kết nối với GitHub.
- Import project từ repository.
- Cấu hình biến môi trường.
- Nhấn "Deploy".
Vercel sẽ tự động nhận diện đây là một dự án Nuxt và build nó một cách chính xác.
Biến môi trường (Environment Variables)
- Trong Nuxt, bạn định nghĩa chúng trong file
.envở thư mục gốc. - Phân biệt biến chỉ dùng ở server và biến có thể truy cập ở client.
API_SECRET=...(Chỉ có ở server)NUXT_PUBLIC_API_BASE=...(Tiền tốNUXT_PUBLIC_cho phép truy cập ở client)
- Truy cập trong code qua
process.env.
🧪 BÀI TẬP LỚN CUỐI CÙNG: Hoàn thiện "SimpleStore" và đưa lên mạng
Mô tả bài toán
Thêm các tính năng cuối cùng vào "SimpleStore" để nó trở thành một ứng dụng full-stack hoàn chỉnh: có API riêng, xác thực người dùng và được tối ưu hóa SEO. Cuối cùng, triển khai ứng dụng.
Yêu cầu
- Xây dựng API riêng:
- Di chuyển logic lấy dữ liệu từ
fakestoreapi.comvào trongserver/api/của bạn. Tạo các endpoint:server/api/products/index.js(lấy danh sách sản phẩm)server/api/products/[id].js(lấy chi tiết sản phẩm)
- Trong các trang của bạn, thay đổi
useFetchđể gọi đến các API nội bộ này (ví dụ:useFetch('/api/products')).
- Di chuyển logic lấy dữ liệu từ
- Tích hợp Authentication:
- Sử dụng
@sidebase/nuxt-authđể thêm tính năng đăng nhập bằng GitHub hoặc Google. - Tạo một trang
/profilechỉ có thể truy cập khi đã đăng nhập. Sử dụng middlewareauth.global.jshoặcdefinePageMetađể bảo vệ route này. - Cập nhật
AppHeaderđể hiển thị trạng thái đăng nhập và nút đăng xuất.
- Sử dụng
- Tối ưu hóa SEO:
- Trên trang chủ, dùng
useHeadđể đặt một title và description mặc định. - Trên trang chi tiết sản phẩm, dùng
useHeadđể đặt title và description động dựa trên thông tin của sản phẩm.
- Trên trang chủ, dùng
- Triển khai lên Vercel:
- Push code của bạn lên một repository mới trên GitHub.
- Deploy dự án lên Vercel.
- Cấu hình các biến môi trường cho OAuth provider trên Vercel dashboard.
- Gửi link ứng dụng đã deploy của bạn để khoe thành quả!
Mục tiêu cuối cùng: Bạn đã xây dựng và triển khai thành công một ứng dụng web full-stack mạnh mẽ bằng Vue và Nuxt, với kiến thức từ frontend đến backend, sẵn sàng để chinh phục bất kỳ dự án nào.
