Muriyi nyigisho, tuzubaka porogaramu nyayo yo kuganira dukoresheje Laravel, Nuxt 3, Sanctum, na Laravel Reverb kugirango dukemure ubutumwa bwizewe kandi bwuzuye hagati yabakoresha. Tuzashyiraho umukoresha wemeza, duhuze na API itekanye, kandi tumenye neza ko ivugurura ryibiganiro ako kanya kuburambe bworoshye kandi bwitondewe.
Tuzakoresha module yo gucunga SPA kwemeza, ikora neza byombi Urupapuro rumwe rukoreshwa (SPA) hamwe no kwemeza API. Kugira ngo umenye byinshi kubyerekeye gukoresha iyi module, reba ingingo kuri Nuxt 3 SPA yo kwemeza .
Muri uyu mushinga, tuzashyiraho Laravel Reverb mugihe nyacyo cyo gutangaza amakuru, dushyire mubikorwa kwemeza hamwe na Sanctum, kandi twubake imbere ya Nuxt 3 yerekana kandi ikayobora ubutumwa bwibiganiro. Reka dutangire!
Ubwa mbere, menya neza ko Laravel Sanctum yashyizweho kandi igashyirwaho. Sanctum yemerera ibimenyetso-byemewe kwemeza urupapuro rumwe rukoreshwa (SPA). Noneho, shyiramo kandi ugene Laravel Reverb kubushobozi-bwigihe.
Ongeraho ibikurikira Reverb ibidukikije bihinduka muri dosiye yawe .env
:
REVERB_APP_ID=my-app-id REVERB_APP_KEY=my-app-key REVERB_APP_SECRET=my-app-secret REVERB_HOST="localhost" REVERB_PORT=8080 REVERB_SCHEME=http
Kubika ubutumwa bwibiganiro, kora iyimuka kumeza chat_messages
. Kwiruka:
php artisan make:migration create_chat_messages_table
Kuvugurura dosiye yimuka kuburyo bukurikira:
Schema::create('chat_messages', function (Blueprint $table) { $table->id(); $table->foreignId('receiver_id'); $table->foreignId('sender_id'); $table->text('text'); $table->timestamps(); });
Koresha kwimuka kugirango ukore imbonerahamwe:
php artisan migrate
Kugirango utangaze ubutumwa mugihe nyacyo, kora MessageSent
bwibikorwa byicyiciro:
php artisan make:event MessageSent
Kuvugurura ibyiciro byibyiciro:
<?php namespace App\Events; use App\Models\ChatMessage; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; class MessageSent implements ShouldBroadcastNow { use Dispatchable, InteractsWithSockets, SerializesModels; public function __construct(public ChatMessage $message) { // } public function broadcastOn(): array { return [new PrivateChannel("chat.{$this->message->receiver_id}")]; } }
channels.php
, sobanura umuyoboro wogutangaza:
Broadcast::channel('chat.{id}', function ($user, $id) { return (int) $user->id === (int) $id; });
Ongeraho izi nzira zo gucunga kohereza no kugarura ubutumwa bwibiganiro:
Route::get('/messages/{user}', function (User $user, Request $request) { return ChatMessage::query() ->where(function ($query) use ($user, $request) { $query->where('sender_id', $request->user()->id) ->where('receiver_id', $user->id); }) ->orWhere(function ($query) use ($user, $request) { $query->where('sender_id', $user->id) ->where('receiver_id', $request->user()->id); }) ->with(['sender', 'receiver']) ->orderBy('id', 'asc') ->get(); })->middleware('auth:sanctum'); Route::post('/messages/{user}', function (User $user, Request $request) { $request->validate(['message' => 'required|string']); $message = ChatMessage::create([ 'sender_id' => $request->user()->id, 'receiver_id' => $user->id, 'text' => $request->message ]); broadcast(new MessageSent($message)); return $message; });
Kwemerera Nuxt 3 guhuza na Reverb, ongeraho ibi bihinduka muri dosiye yawe .env
:
NUXT_PUBLIC_REVERB_APP_ID=my-app-id NUXT_PUBLIC_REVERB_APP_KEY=my-app-key NUXT_PUBLIC_REVERB_APP_SECRET=my-app-secret NUXT_PUBLIC_REVERB_HOST="localhost" NUXT_PUBLIC_REVERB_PORT=8080 NUXT_PUBLIC_REVERB_SCHEME=http
Noneho, ubishyire muri nuxt.config.ts
:
export default defineNuxtConfig({ runtimeConfig: { public: { REVERB_APP_ID: process.env.NUXT_PUBLIC_REVERB_APP_ID, REVERB_APP_KEY: process.env.NUXT_PUBLIC_REVERB_APP_KEY, REVERB_APP_SECRET: process.env.NUXT_PUBLIC_REVERB_APP_SECRET, REVERB_HOST: process.env.NUXT_PUBLIC_REVERB_HOST, REVERB_PORT: process.env.NUXT_PUBLIC_REVERB_PORT, REVERB_SCHEME: process.env.NUXT_PUBLIC_REVERB_SCHEME, }, }, });
Gucunga amakuru yigihe-gihe, kora laravel-echo.client.ts
plugin:
import Echo from "laravel-echo"; import Pusher, { type ChannelAuthorizationCallback } from "pusher-js"; declare global { interface Window { Echo: Echo; Pusher: typeof Pusher; } } export default defineNuxtPlugin(() => { window.Pusher = Pusher; const config = useRuntimeConfig(); const echo = new Echo({ broadcaster: "reverb", key: config.public.REVERB_APP_KEY, wsHost: config.public.REVERB_HOST, wsPort: config.public.REVERB_PORT ?? 80, wssPort: config.public.REVERB_PORT ?? 443, forceTLS: (config.public.REVERB_SCHEME ?? "https") === "https", enabledTransports: ["ws", "wss"], authorizer: (channel, options) => ({ authorize: (socketId, callback) => { useSanctumFetch("api/broadcasting/auth", { method: "post", body: { socket_id: socketId, channel_name: channel.name }, }) .then(response => callback(null, response)) .catch(error => callback(error, null)); }, }), }); return { provide: { echo } }; });
Kugirango ushoboze kuganira mugihe nyacyo muri porogaramu yacu ya Nuxt 3, nashizeho page nshya, chats > [id].vue
, aho abakoresha bashobora guhitamo no kuganira nabandi bakoresha. Uru rupapuro ruhuza inyuma ya Laravel kugirango ucunge ubutumwa bwibiganiro hamwe namakuru yumukoresha, ukoresheje Laravel Echo na WebSockets mugihe nyacyo cyo kuvugurura no kwerekana ibimenyetso.
Dore ibice byuburyo twateguye iyi mikorere yo kuganira:
Ubwa mbere, dukura userID
muri URL hamwe no useRoute
ihimbye. Uyu userID
yerekana umukoresha tuganira kandi yikoreza umukoresha n'ubutumwa bwo kuganira.
const route = useRoute(); const userID = route.params.id; const { user: currentUser } = useSanctum<User>(); const { data: user } = await useAsyncData( `user-${userID}`, () => useSanctumFetch<User>(`/api/users/${userID}`) ); const { data: messages } = useAsyncData( `messages-${userID}`, () => useSanctumFetch<ChatMessage[]>(`/api/messages/${userID}`), { default: (): ChatMessage[] => [] } );
Aka gatabo gakoresha useSanctumFetch
, yihariye igizwe, kugirango yikoreze ubutumwa butajegajega iyo page ihagaze.
Dutanga buri butumwa muburyo bukomeye, tukabushushanya dukurikije niba bituruka kubakoresha ubu cyangwa abitabiriye ibiganiro.
<div ref="messagesContainer" class="p-4 overflow-y-auto max-h-fit"> <div v-for="message in messages" :key="message.id" class="flex items-center mb-2"> <div v-if="message.sender_id === currentUser.id" class="p-2 ml-auto text-white bg-blue-500 rounded-lg"> {{ message.text }} </div> <div v-else class="p-2 mr-auto bg-gray-200 rounded-lg"> {{ message.text }} </div> </div> </div>
Idirishya ryibiganiro rihita ryerekeza kubutumwa buheruka ukoresheje nextTick()
.
watch( messages, () => { nextTick(() => messageContainerScrollToBottom()); }, { deep: true } ); function messageContainerScrollToBottom() { if (!messagesContainer.value) return; messagesContainer.value.scrollTo({ top: messagesContainer.value.scrollHeight, behavior: 'smooth' }); }
Abakoresha barashobora kohereza ubutumwa hamwe numwanya winjiza. Mugihe cyoherejwe, icyifuzo cya POST cyoherejwe inyuma ya Laravel.
const newMessage = ref(""); const sendMessage = async () => { if (!newMessage.value.trim()) return; const messageResponse = await useSanctumFetch<ChatMessage>(`/api/messages/${userID}`, { method: "post", body: { message: newMessage.value } }); messages.value.push(messageResponse); newMessage.value = ""; };
Ubutumwa buravugururwa ako kanya nyuma yo koherezwa.
Laravel Echo yumva ibintu byingenzi nka MessageSent
no typing
.
onMounted(() => { if (currentUser.value) { $echo.private(`chat.${currentUser.value.id}`) .listen('MessageSent', (response: { message: ChatMessage }) => { messages.value.push(response.message); }) .listenForWhisper("typing", (response: { userID: number }) => { isUserTyping.value = response.userID === user.value?.id; if (isUserTypingTimer.value) clearTimeout(isUserTypingTimer.value); isUserTypingTimer.value = setTimeout(() => { isUserTyping.value = false; }, 1000); }); } });
Ibi bikora ubutumwa bwigihe-gihe cyo kuvugurura no kwandika ibipimo, bikabura nyuma yisegonda yo kudakora.
Kugirango twerekane icyerekezo cyo kwandika, dukurura "kwandika" ibyabaye whisper
.
const sendTypingEvent = () => { if (!user.value || !currentUser.value) return; $echo.private(`chat.${user.value.id}`).whisper("typing", { userID: currentUser.value.id }); };
Ibirori byoherejwe igihe cyose umukoresha yanditse, kandi uyahawe abona icyerekezo cyo kwandika.
Isohora ryibiganiro ririmo umutwe hamwe nizina ryatoranijwe ryumukoresha nibice byubutumwa hamwe numwanya winjiza.
<template> <div> <header v-if="user" class="bg-white shadow"> <div class="px-4 py-6 mx-auto max-w-7xl sm:px-6 lg:px-8"> <h1 class="text-2xl font-bold ">{{ user.name }}</h1> </div> </header> <div class="flex flex-col items-center py-5"> <div class="container w-full h-full p-8 space-y-3 bg-white rounded-xl"> <div v-if="currentUser"> <div class="flex flex-col justify-end h-80"> <div ref="messagesContainer" class="p-4 overflow-y-auto max-h-fit"> <div v-for="message in messages" :key="message.id" class="flex items-center mb-2"> <div v-if="message.sender_id === currentUser.id" class="p-2 ml-auto text-white bg-blue-500 rounded-lg"> {{ message.text }} </div> <div v-else class="p-2 mr-auto bg-gray-200 rounded-lg"> {{ message.text }} </div> </div> </div> </div> <div class="flex-shrink-0"> <span v-if="user && isUserTyping" class="text-gray-500"> {{ user.name }} is typing... </span> <div class="flex items-center justify-between w-full p-4 border-t border-gray-200"> <input type="text" v-model="newMessage" @keydown="sendTypingEvent" @keyup.enter="sendMessage" class="w-full p-2 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Type a message..." /> <button @click.prevent="sendMessage" class="inline-flex items-center justify-center w-12 h-12 ml-4 text-white bg-blue-500 rounded-lg hover:bg-blue-600"> <svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3" /> </svg> </button> </div> </div> </div> </div> </div> </div> </template>
Ibi birangiza igihe nyacyo cyo kuganira ukoresheje Laravel Sanctum na Echo hamwe na Nuxt 3.
Ubu twashizeho porogaramu itekanye, mugihe nyacyo cyo kuganira dukoresheje Laravel, Sanctum, Reverb, na Nuxt 3. Iyi mikorere irashobora kugabanywa byoroshye kugirango ushiremo ibintu byongeweho nkibisubizo byubutumwa cyangwa ibyumba byinshi byo kuganiriramo.
Kode yuzuye, sura ububiko bwa GitHub .