Membuat realtime chat

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 ( {messages.map((msg, index) => ( {msg.content} ))} setContent(e.target.value)} /> Send ); }; 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 ru

Mar 19, 2025 - 17:28
 0
Membuat realtime chat

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.