Jak zbudować społeczność online w Next.js

Forum przechowuje to, co napisali jego członkowie. Społeczność, która sprawia wrażenie żywej, oferuje więcej naraz. Członkowie dzielą się zdjęciem i dostają odpowiedź, póki jeszcze są na miejscu, wchodzą do pokoju, żeby porozmawiać, głosem albo przed kamerą, oglądają wydarzenia klubu na żywo i wchodzą na scenę z własną pracą, a do tego widzą, kto jest teraz obecny. W aplikacji Next.js każda z tych rzeczy to połączenie, które zostaje otwarte, z wieloma osobami naraz.
Ten wpis omawia każdą część, której potrzebuje prawdziwa aplikacja społecznościowa, na pełnym, działającym przykładzie: Community, klubie fotograficznym z naszego przewodnika po Next.js, z jego kanałami, pokojami, do których można wpaść, i wydarzeniami na żywo. Możesz wypróbować go na żywo: zaloguj się jako Mia, gospodarz klubu. Przegląd portfolio zaczyna się właśnie teraz, więc otwórz studio i wejdź na żywo. Potem otwórz klub w oknie prywatnym jako Ava, oglądaj przegląd, podnieś rękę i wejdź na scenę.
Czego potrzebuje społeczność online
- Kanały, które nadążają. Wiadomości i zdjęcia od razu docierają do wszystkich, którzy czytają, z informacją, kto pisze, i z reakcjami, a potem zostają zapisane dla tych, którzy przyjdą później. Zdjęcia otwierają się tylko członkom.
- Pokoje, do których się wpada. Pokoje głosowe oraz pokoje z kamerami i ekranami, do których członkowie wchodzą i z których wychodzą, kiedy chcą, wiele osób naraz przez serwery mediów (jak działają serwery mediów). Gospodarze, którzy mogą kogoś wyciszyć albo usunąć.
- Wydarzenia na żywo. Jeden gospodarz dla wszystkich członków, z czatem i reakcjami obok obrazu, i członek zaproszony na scenę, żeby pokazać swoją pracę (jak działają transmisje na żywo w Next.js).
- Co się teraz dzieje. Kto jest w którym pokoju i które wydarzenie trwa na żywo, aktualne na każdej stronie, bez przeładowania.
- Kto jest obecny. Kto jest online i sposób, by do tej osoby napisać albo zadzwonić.
Wszystko to działa na połączeniach, które zostają otwarte, dopóki członek jest w serwisie, a tego funkcja serverless nie utrzyma (dlaczego i co z tym zrobić). Każdą część możesz zbudować sam, na websocketach, WebRTC i własnych serwerach mediów. Albo oddajesz połączenia, rozmowy i transmisje chmurze czasu rzeczywistego, a Twój serwer zachowuje to, co naprawdę należy do Ciebie: członków, reguły i dane. Tak działa klub, z WordPlus Cloud.
Przykład: klub fotograficzny
Członkowie dzielą się zdjęciami w kanałach, żeby dostać opinię, na przykład w #critique i #trips. Wpadają do jego pokojów: do Coffee lounge głosem, do Editing hangout z kamerami i ekranami. Gospodarze prowadzą wydarzenia na żywo, przegląd portfolio albo kurs fotografii nocnej, na których członkowie wchodzą na scenę. To aplikacja Next.js z App Routerem, Better Auth i Postgresem, a jej część czasu rzeczywistego to kilka plików. Pięć kroków ją tworzy.
1. Kanały ze zdjęciami, przechowywane na Twoim serwerze
Każdy kanał to pokój nazwany swoim numerem: channel:2. Serwis deklaruje je raz, według tego wzorca, z regułą, kto może w nim być:
const MESSAGES = { history: 50, emit: ['message', 'typing', 'reaction', 'read'], webhook: ['message', 'reaction'] };
realtime.room('channel:{id}', MESSAGES, async (user, _params, room) => mayWrite(user, room));Każdy członek może być w kanale, a nikt inny. Wiadomości, informacja, kto pisze, reakcje i potwierdzenia przeczytania przechodzą ze strony na stronę przez WordPlus Cloud, zapieczętowane, a webhooki message i reaction przynoszą każdą z nich na serwer serwisu, który zapisuje ją we własnej bazie danych. Strona kanału to gotowy czat na tym pokoju:
<Chat
rt={useRealtime()}
room={room}
people={people}
messages={`/api/messages?room=${room}`}
upload="/api/files"
accept="image/jpeg,image/png,image/webp,image/gif"
maxFileSize={15 * 1024 * 1024}
/>messages to własna ścieżka serwisu do starszych wiadomości, doczytywanych, gdy członek przewija w górę. upload daje polu wpisywania spinacz i przyjmuje też zdjęcia wklejone albo upuszczone na czat: każde trafia na własną ścieżkę serwisu, gdy tylko zostanie wybrane, a wiadomość niesie tylko miejsce, w którym się otwiera. WordPlus Cloud nigdy nie widzi zdjęcia. Ścieżka decyduje według reguły samego pokoju:
if (!me || !(file instanceof File) || !/^(channel|chat):\d+$/.test(room) || !(await realtime.mayJoin(room, me))) {
return Response.json({ error: 'This photo is not for this conversation.' }, { status: 403 });
}realtime.mayJoin() uruchamia tę samą regułę co wejście do pokoju, więc kto może czytać kanał, może w nim udostępnić zdjęcie, a nikt inny. Każde zdjęcie otwiera się pod własnym adresem, który znów sprawdza, kto je otwiera: ktoś spoza klubu nie dostaje nic, bez względu na to, jaki adres zna.
2. Pokoje głosowe, o które dbają gospodarze
Pokój to rozmowa grupowa nazwana swoim numerem, lounge:3, do której może wpaść każdy członek. Reguła czyni gospodarzy klubu jej gospodarzami:
realtime.groupCalls('lounge:{id}', async (user) => {
if (!(await isMember(user))) return false;
return (await isHost(user)) ? { admin: true } : true;
});Pokój pokazuje się na własnej stronie, z przyciskiem wejścia w środku:
<CallSpot rt={rt} call={room} className="h-[calc(100dvh-14rem)] rounded-2xl">
<GroupCallButton rt={rt} room={room} type={kind} title={name}>
{people.length > 0 ? 'Drop in' : `Open ${name}`}
</GroupCallButton>
</CallSpot>type to audio dla pokoju głosowego i video dla pokoju z kamerami. Zanim członek wejdzie, CallSpot pokazuje to, co jest w środku: kto jest teraz w pokoju, i przycisk. Po wejściu rozmowa zajmuje to miejsce: obraz każdego albo kamery i ekrany wszystkich, oraz przyciski sterowania. Członek wchodzi z wyłączonym mikrofonem i kamerą i włącza je z rozmowy, więc wpadnięcie do pokoju nigdy nie otwiera mikrofonu niespodziewanie. Na innej stronie serwisu pokój trwa w okienku w rogu i wraca, gdy jego strona znów się otworzy.
admin: true to wszystko, czego potrzebują gospodarze. Na ekranie gospodarza każdy kafelek pozostałych ma wyciszenie i usunięcie, o które ekran rozmowy prosi tą samą ścieżką, a ona przyjmuje je tylko od gospodarza.
3. Wydarzenia na żywo, z członkami na scenie
Wydarzenie to transmisja na żywo nazwana swoim numerem: event:5. Jej reguła mówi, kto jest kim: gospodarz wydarzenia wchodzi na żywo, a każdy inny członek ogląda:
realtime.streams(
'event:{id}',
async (user, { id }) => {
const event = await eventOf(id);
if (!event || !(await isMember(user))) return false;
return String(user) === event.host ? { role: 'host', quality: '1080p' } : 'viewer';
},
{ stage: true, reactions: true },
);Gospodarz wchodzi na żywo z własnego studia, strony serwisu z dużym obrazem, Go live pod nim, a obok czatem i podniesionymi rękami:
<LiveStream
name={`event:${event.id}`}
view="studio-page"
title={event.title}
url={`/events/${event.id}`}
backUrl={`/events/${event.id}`}
/>Strona wydarzenia daje każdemu członkowi odtwarzacz z czatem, ten sam <LiveStream> pod tą samą nazwą. Gospodarz może też wejść na żywo z OBS, z adresem i kluczem, które podaje studio. stage: true to scena: członek podnosi rękę w odtwarzaczu, gospodarz widzi ją w Guests i zaprasza tę osobę, a gdy tylko naciśnie ona Join stage, jej kamera i mikrofon wchodzą na żywo obok gospodarza, dla wszystkich, którzy oglądają.
4. Co się teraz dzieje, na każdej stronie
Obok każdej strony pasek boczny pokazuje, kto jest w którym pokoju i które wydarzenie trwa na żywo, z liczbą widzów. Serwis nie prowadzi żadnej tabeli tych rzeczy. Wie to WordPlus Cloud:
export async function liveNow(): Promise<Map<string, number>> {
const live = new Map<string, number>();
for (const stream of await realtime.listStreams()) {
const event = idIn(stream.name, 'event');
if (event) live.set(event, stream.viewers);
}
return live;
}realtime.listCalls() i realtime.call(name).get() mówią to samo o pokojach i o tym, kto jest w każdym z nich. Żeby wszystko było aktualne, WordPlus Cloud wysyła serwisowi webhook za każdym razem, gdy ktoś wchodzi do pokoju albo z niego wychodzi, albo gdy wydarzenie zaczyna się lub kończy. Serwis mówi o tym w pokoju, do którego dołącza każda strona członka, a gdy wydarzenie wchodzi na żywo, powiadamia każdego członka:
realtime.on('stream.live', async ({ stream }) => {
const id = idIn(stream, 'event');
const event = id ? await eventOf(id) : null;
if (!event) return;
await realtime.to('club').emit('changed');
const everyone = (await members()).map((person) => person.id).filter((person) => person !== event.host);
await realtime.toUser(everyone).emit('live', { event: event.id, title: event.title, host: event.hostName });
});W layoucie każda strona słyszy jedno i drugie:
useRoom('club', { changed: () => router.refresh() });
useUserEvent('live', (data: { event: string; title: string; host: string }) => {
if (path !== `/events/${data.event}`) show({ text: `${data.host} is live: ${data.title}`, href: `/events/${data.event}`, live: true });
});Pierwsze sprawia, że każda strona prosi serwer o siebie na nowo, bez przeładowania, więc pasek boczny i otwarta strona pozostają aktualne. Drugie pokazuje powiadomienie na dowolnej stronie, na której jest członek: „Mia is live: Live portfolio review”, które otwiera wydarzenie. group.joined, group.left i stream.ended mówią changed w tym samym pokoju.
5. Kto jest online
WordPlus Cloud wie, kto jest online: każda strona, za której członka serwis poręczył, sprawia, że ten członek jest online, a strona dowiaduje się, kto przychodzi i odchodzi, bez żadnego zapytania do serwera serwisu:
const { online } = useOnline(people.map((person) => person.id));
const here = people.filter((person) => online[person.id]);
const away = people.filter((person) => !online[person.id]);Lista członków pokazuje najpierw tych, którzy są online, każdego z Message i Call, a obok każdej strony layout wymienia klub tak samo, z zaznaczonymi gospodarzami. Strona członka mówi, czy ta osoba jest online, albo kiedy była ostatnio widziana.
Co jest w zestawie
- Rozmowy we dwoje. Strona członka zawiera Twój czat z tą osobą, razem ze zdjęciami, a Wasza rozmowa pokazuje się obok wiadomości.
- Reakcje i czat przy każdym wydarzeniu, obok obrazu, i wejście na żywo z OBS albo dowolnego enkodera, który wysyła przez WHIP.
- Udostępnianie ekranu w pokoju z kamerami, z przycisków sterowania rozmową.
- Imiona i twarze z Twojej aplikacji. Każdy kafelek, każda wiadomość i scena pokazują imię i zdjęcie członka tak, jak podaje je
profileserwisu, bez listy użytkowników przechowywanej w WordPlus Cloud. - Odbieranie dostępu. Gdy ktoś opuszcza klub, reguły od tej pory odmawiają, a
realtime.call(name).remove(user)od razu usuwa tę osobę z pokoju.
Wypróbuj, a potem zbuduj własną
W demo na żywo klub należy tylko do Ciebie przez dobę, więc nikt inny nie widzi, czym się tam dzielisz ani kogo spotykasz, a wydarzenie albo pokój same kończą się po 10 minutach. Pod każdą stroną panel How this page works pokazuje kod, który ją tworzy, krok po kroku, z wartościami strony, którą masz otwartą.
Przewodnik po serwisie społecznościowym buduje cały serwis, z każdym plikiem jego części czasu rzeczywistego w całości. Transmisje na żywo w Next.js i rozmowy w Next.js pokazują wszystkie sposoby umieszczenia transmisji albo rozmowy we własnej aplikacji. Dla zespołu zamiast klubu wideokonferencje w Next.js budują spotkania intranetu firmowego.
WordPlus Cloud for Apps ma cenę według jednoczesnych połączeń, od 1000 wzwyż, rozliczaną miesięcznie lub rocznie. Przy 1000 połączeń transmisje na żywo nie są naliczane do 50 widzów jednocześnie, a rozmowy grupowe do 32 osób z wideo jednocześnie, przy czym osoba z samym dźwiękiem liczy się za pół. Każde kolejne 1000 połączeń dodaje 20 widzów i 12 osób z wideo. Powyżej każdy dodatkowy widz albo osoba z wideo zużywa kredyt na minutę, transmisja liczona tylko wtedy, gdy trwa, a rozmowy między dwiema osobami nie zużywają kredytów. Zobacz transmisje na żywo dla aplikacji, rozmowy wideo dla aplikacji albo cennik dla aplikacji. Chcesz zapytać o swoją integrację? Napisz do nas.