Dalam artikel ini, kita akan membuat aplikasi Next.js dari awal dengan Prisma sebagai ORM, Socket.io untuk real-time chat, dan tanpa backend terpisah.
Semua dijalankan dalam satu proses menggunakan npm run dev
.
1. Membuat Proyek Next.js
Pertama, buat proyek baru menggunakan Next.js:
npx create-next-app@latest my-app --ts --tailwind
cd my-app
Jalankan proyek:
npm run dev
Buka http://localhost:3000 untuk melihat tampilan default Next.js.
2. Setup Prisma di Next.js
Install Prisma dan klien database:
npm install @prisma/client @prisma/cli
npx prisma init
Buka file prisma/schema.prisma
dan ubah skema sebagai berikut:
model User {
id String @id @default(uuid())
name String
email String @unique
}
model Message {
id String @id @default(uuid())
senderId String
recipientId String
content String
createdAt DateTime @default(now())
sender User @relation(fields: [senderId], references: [id])
recipient User @relation(fields: [recipientId], references: [id])
}
Jalankan migrasi:
npx prisma migrate dev --name init
Buat file /lib/prisma.ts
untuk mencegah banyak instance Prisma:
import { PrismaClient } from "@prisma/client";
const globalForPrisma = global as unknown as { prisma?: PrismaClient };
export const prisma = globalForPrisma.prisma ?? new PrismaClient();
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
Buat fungsi database di /lib/messages.ts
:
import { prisma } from "./prisma";
export const sendMessage = async (senderId: string, recipientId: string, content: string) => {
return prisma.message.create({ data: { senderId, recipientId, content } });
};
export const getMessages = async (userId: string) => {
return prisma.message.findMany({
where: { OR: [{ senderId: userId }, { recipientId: userId }] },
orderBy: { createdAt: "asc" },
});
};
3. Setup Socket.io di Next.js
Install Socket.io:
npm install socket.io socket.io-client
Buat file /lib/socket.ts
untuk menangani koneksi Socket.io:
import { Server as HttpServer } from "http";
import { Server as SocketIOServer } from "socket.io";
import { sendMessage } from "./messages";
let io: SocketIOServer | null = null;
export const initSocket = (server: HttpServer) => {
if (!io) {
io = new SocketIOServer(server, { cors: { origin: "*" } });
io.on("connection", (socket) => {
console.log("User connected:", socket.id);
socket.on("sendMessage", async (data) => {
const message = await sendMessage(data.senderId, data.recipientId, data.content);
io?.emit("newMessage", message);
});
socket.on("disconnect", () => console.log("User disconnected:", socket.id));
});
}
};
Tambahkan server.ts
untuk menjalankan Next.js dan Socket.io dalam satu proses:
import { createServer } from "http";
import { initSocket } from "./lib/socket";
import next from "next";
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });
const handle = app.getRequestHandler();
app.prepare().then(() => {
const server = createServer((req, res) => handle(req, res));
initSocket(server);
server.listen(3000, () => {
console.log("Server running on http://localhost:3000");
});
});
Tambahkan ke package.json
:
"scripts": {
"dev": "node server.ts"
}
4. Menggunakan Socket.io di Frontend
Buat hook /lib/useChat.ts
:
import { useEffect, useState } from "react";
import { io } from "socket.io-client";
const socket = io("http://localhost:3000");
export const useChat = () => {
const [messages, setMessages] = useState([]);
useEffect(() => {
socket.on("newMessage", (message) => {
setMessages((prev) => [...prev, message]);
});
return () => {
socket.off("newMessage");
};
}, []);
const sendMessage = (senderId: string, recipientId: string, content: string) => {
socket.emit("sendMessage", { senderId, recipientId, content });
};
return { messages, sendMessage };
};
5. Membuat UI Chat
Di dalam components/Chat.tsx
:
"use client";
import { useChat } from "@/lib/useChat";
import { useState } from "react";
export const Chat = ({ userId }: { userId: string }) => {
const { messages, sendMessage } = useChat();
const [content, setContent] = useState("");
const handleSend = () => {
sendMessage(userId, "recipient-id", content);
setContent("");
};
return (
<div className="p-4 border border-gray-300 rounded-md w-96">
<div className="h-60 overflow-y-auto border-b border-gray-300 mb-2 p-2">
{messages.map((msg, index) => (
<div key={index} className="p-2 bg-gray-100 rounded-md my-1">
{msg.content}
</div>
))}
</div>
<div className="flex gap-2">
<input
className="flex-1 p-2 border rounded-md"
value={content}
onChange={(e) => setContent(e.target.value)}
/>
<button className="bg-blue-500 text-white px-4 py-2 rounded-md" onClick={handleSend}>
Send
</button>
</div>
</div>
);
};
Kesimpulan
Dengan pendekatan ini:
- Next.js digunakan sebagai frontend dan backend dalam satu proses.
- Prisma dikelola langsung tanpa API Routes.
- Socket.io berjalan dalam server Next.js.
- Chat real-time bisa langsung digunakan dengan
npm run dev
.
Pendekatan ini sangat cocok untuk proyek sederhana tanpa backend terpisah.
Top comments (0)