WebSocket temps réel avec Claude Code
Découvrez webSocket temps réel avec Claude Code. Conseils pratiques et exemples de code inclus.
リアルタイム通信開発でClaude Codeを活用する
チャット、通知、共同Editなど、リアルタイム通信が必要なアプリケーションは増えています。Claude Codeはサーバーサイドとクライアントサイドの両方を理解した上で、一貫した実装を支援します。
Socket.IOによるチャット機能の実装
> Socket.IOを使ったリアルタイムチャットのサーバーを作成して。
> ルーム機能、タイピングインジケーター、既読機能を実装して。
サーバーサイド
import express from 'express';
import { createServer } from 'http';
import { Server, Socket } from 'socket.io';
const app = express();
const server = createServer(app);
const io = new Server(server, {
cors: { origin: 'http://localhost:5173' },
});
interface ChatMessage {
id: string;
roomId: string;
userId: string;
content: string;
timestamp: Date;
}
const rooms = new Map<string, Set<string>>();
io.on('connection', (socket: Socket) => {
const userId = socket.handshake.auth.userId;
console.log(`User connected: ${userId}`);
socket.on('join-room', (roomId: string) => {
socket.join(roomId);
if (!rooms.has(roomId)) rooms.set(roomId, new Set());
rooms.get(roomId)!.add(userId);
socket.to(roomId).emit('user-joined', {
userId,
members: Array.from(rooms.get(roomId)!),
});
});
socket.on('send-message', async (data: { roomId: string; content: string }) => {
const message: ChatMessage = {
id: crypto.randomUUID(),
roomId: data.roomId,
userId,
content: data.content,
timestamp: new Date(),
};
// Save to DB
await saveMessage(message);
io.to(data.roomId).emit('new-message', message);
});
socket.on('typing-start', (roomId: string) => {
socket.to(roomId).emit('user-typing', { userId, isTyping: true });
});
socket.on('typing-stop', (roomId: string) => {
socket.to(roomId).emit('user-typing', { userId, isTyping: false });
});
socket.on('mark-read', (data: { roomId: string; messageId: string }) => {
socket.to(data.roomId).emit('message-read', {
userId,
messageId: data.messageId,
});
});
socket.on('disconnect', () => {
rooms.forEach((members, roomId) => {
if (members.delete(userId)) {
io.to(roomId).emit('user-left', { userId });
}
});
});
});
server.listen(3000, () => console.log('Server running on port 3000'));
クライアントサイド(React)
import { useEffect, useState, useCallback } from 'react';
import { io, Socket } from 'socket.io-client';
let socket: Socket;
export function useChat(roomId: string, userId: string) {
const [messages, setMessages] = useState<ChatMessage[]>([]);
const [typingUsers, setTypingUsers] = useState<Set<string>>(new Set());
useEffect(() => {
socket = io('http://localhost:3000', { auth: { userId } });
socket.emit('join-room', roomId);
socket.on('new-message', (message: ChatMessage) => {
setMessages(prev => [...prev, message]);
});
socket.on('user-typing', ({ userId: uid, isTyping }) => {
setTypingUsers(prev => {
const next = new Set(prev);
isTyping ? next.add(uid) : next.delete(uid);
return next;
});
});
return () => { socket.disconnect(); };
}, [roomId, userId]);
const sendMessage = useCallback((content: string) => {
socket.emit('send-message', { roomId, content });
}, [roomId]);
const startTyping = useCallback(() => {
socket.emit('typing-start', roomId);
}, [roomId]);
const stopTyping = useCallback(() => {
socket.emit('typing-stop', roomId);
}, [roomId]);
return { messages, typingUsers, sendMessage, startTyping, stopTyping };
}
Server-Sent Events(SSE)による通知
WebSocketほどの双方向性が不要な場合、SSEが軽量な選択肢です。
// server
app.get('/api/notifications/stream', (req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
Connection: 'keep-alive',
});
const userId = req.query.userId as string;
const sendEvent = (data: object) => {
res.write(`data: ${JSON.stringify(data)}\n\n`);
};
// 新しい通知があれば送信
const unsubscribe = notificationBus.subscribe(userId, sendEvent);
req.on('close', () => {
unsubscribe();
res.end();
});
});
// client
function useNotifications(userId: string) {
const [notifications, setNotifications] = useState<Notification[]>([]);
useEffect(() => {
const eventSource = new EventSource(
`/api/notifications/stream?userId=${userId}`
);
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
setNotifications(prev => [data, ...prev]);
};
return () => eventSource.close();
}, [userId]);
return notifications;
}
接続の安定性を高める
本番環境では、再接続ロジックやハートビートの実装が重要です。
const socket = io('http://localhost:3000', {
auth: { userId },
reconnection: true,
reconnectionAttempts: 10,
reconnectionDelay: 1000,
reconnectionDelayMax: 5000,
timeout: 20000,
});
socket.on('connect_error', (err) => {
console.error('Connection error:', err.message);
});
socket.on('reconnect', (attempt) => {
console.log(`Reconnected after ${attempt} attempts`);
// Reconnect後にルームに再参加
socket.emit('join-room', currentRoomId);
});
Summary
Claude Codeを活用すれば、WebSocketやSSEを使ったリアルタイム通信機能をサーバー・クライアント両方一貫して実装できます。プロンプトの書き方次第でコードの質が大きく変わるため、プロンプトテクニックを身につけておくことが重要です。個人開発でチャット機能を実装する際は個人開発を爆速にする方法も参考にしてください。
詳しくはAnthropic公式ドキュメントやSocket.IO公式ドキュメントをご覧ください。
Related Posts
Comment booster vos projets personnels avec Claude Code [Avec exemples]
Apprenez à accélérer considérablement vos projets de développement personnels avec Claude Code. Inclut des exemples concrets et un workflow pratique de l'idée au déploiement.
Comment automatiser le refactoring avec Claude Code
Apprenez à automatiser efficacement le refactoring de code avec Claude Code. Inclut des prompts pratiques et des patterns de refactoring concrets pour des projets réels.
Guide complet de configuration CORS avec Claude Code
Découvrez le guide complet de configuration CORS avec Claude Code. Conseils pratiques et exemples de code inclus.