Vytvoření klonu Clubhouse se Svelte a 100 ms

V tomto článku si projdeme proces budování klonu Clubhouse se 100 ms a Svelte. Klubovna je oblíbená aplikace, která umožňuje lidem mluvit spolu v audio místnostech přes internet.

Tento obsah byl původně publikován – ZDE

Co je Svelte?

Svelte je nový rámec, který zavádí zcela nový způsob interakce rámců s DOM. Nepoužívá VDOM, ale chirurgicky aktualizuje DOM na základě toho, co chcete zobrazit.

Máme také podrobné průvodce, jak vytvořit aplikaci podobnou Clubhouse s různými technologiemi

  • Klon Clubhouse s 100 ms iOS SDK
  • Klon Clubhouse s 100 ms React SDK
  • Klon Clubhouse s 100 ms Flutter SDK
  • Klon Clubhouse s 100 ms Javascript SDK

Je také lehký, a tím pádem rychlejší, protože se do frontendu nedodává štíhlý. Místo toho dodává kód, který provádí aktualizaci.

Co je 100 ms?

100 ms poskytuje infrastrukturu pro videokonference navrženou tak, aby podnikům pomohla vytvořit výkonné video aplikace během několika hodin. Jeho SDK je přizpůsobeno tak, aby vyhovovalo mnoha případům použití, jako je streamování her, virtuální události, zvukové místnosti, učebny a mnoho dalšího. Abstrahuje složitosti spojené s vytvářením těchto aplikací a výrazně zkracuje dobu vývoje.

Ke všemu bylo vytvořeno 100 ms a je spravováno týmem, který vytvořil živou infrastrukturu ve společnostech Disney a Facebook (Meta).

Předpoklady

  • Správná znalost jazyka Javascript
  • Účet 100 ms; pokud jej nemáte, můžete si vytvořit svůj účet zde

Vysvětlení pojmů 100 ms

Existuje několik termínů používaných 100 ms, se kterými se musíme seznámit, abychom porozuměli tomuto článku:

  • Místnost: Místnost je základní objekt, který 100ms SDK vrátí při úspěšném připojení. Obsahuje odkazy na kolegy, stopy a vše, co potřebujete k vykreslení živé audio/vizuální aplikace.
  • Partner: Peer je objekt vrácený 100 ms SDK, který obsahuje všechny informace o uživateli:jméno, roli, stopu videa atd.
  • Track: Stopa představuje zvuk nebo video, které partner publikuje.
  • Role: Role definuje, koho může partner vidět/slyšet, kvalitu, ve které své video publikuje, zda má oprávnění publikovat video/sdílet obrazovku, někoho ztlumit a/nebo změnit něčí roli.

O dalších podmínkách si můžete přečíst zde

Kroky kolem 100 ms

  • Nastavení 100 ms
  • Vytvoření účtu
  • Vytváření rolí a místností

Kroky kolem nastavení rozhraní Frontend

  • Přidejte aplikaci Svelte 100 ms
  • Připojit se k místnosti
  • Opustit místnost
  • Ignorovat/zrušit ignorování partnera
  • Chat v místnosti

Nastavení 100 ms

-Přihlaste se ke svému účtu 100 ms. Na hlavním panelu klikněte na Přidat novou aplikaci Knoflík.

  • Vyberte pro svou aplikaci subdoménu.

  • Vyberte šablonu pro aplikaci. Vzhledem k tomu, že budujeme klon klubovny, 'Audio Rooms' nám poskytnou správné nastavení ihned po vybalení. Vyberte tuto možnost.

  • To by se pak mělo zobrazit na obrazovce.

Klikněte na kteroukoli možnost Připojit se jako tlačítka pro otestování platformy.

Chcete-li ušetřit čas, přejděte na kartu Vývojář na řídicím panelu, zkopírujte koncový bod tokenu a uložte jej na bezpečném místě. Dále přejděte na kartu Pokoje a uložte ID místnosti místnosti, kterou jsme právě vytvořili.

Nastavení rozhraní

Chcete-li začít, naklonujte tento startovací balíček. Obsahuje hlavní nastavení potřebné pro aplikaci, jako je SCSS a směrování stránek a také její součásti. Po klonování spusťte

yarn

k instalaci všech závislostí startovacího balíčku.

Běh

yarn dev

k zahájení projektu. Měli byste vidět následující:

Pod src/services/hms.js , nastavili jsme základní funkce 100 ms. Tyto funkce nám umožňují připojit naše komponenty do 100 ms.

Zamiřte do App.svelte soubor v src a jeho obsah nahradit:

<script>
  import router from "page";
  import Home from "./pages/home.svelte";
  import Room from "./pages/room.svelte";
//NEW LINE HERE
  import { onMount } from "svelte";
  import { hmsStore } from "./services/hms";
  import { selectIsConnectedToRoom } from "@100mslive/hms-video-store";
//NEW LINE ENDS

  let page;

  router("/", () => (page = Home));

  router("/room", () => (page = Room));

  router.start();
//NEW LINE HERE
  const onRoomStateChange = (connected) => {
    if (connected) router.redirect("/room");
    else router.redirect("/");
  };

  onMount(async () => {
    hmsStore.subscribe(onRoomStateChange, selectIsConnectedToRoom);
  });
//NEW LINE ENDS
</script>

<svelte:component this={page} />

Při postupu shora jsou importovány 3 nové proměnné:

  • onMount: Toto je funkce od Svelte, která se spouští po připojení komponenty (například componentDidMount v Reactu). Používáte ho hlavně k odběru posluchačů nebo odesílání požadavků na koncové body API.
  • hmsStore: Obsahuje kompletní stav místnosti v daném okamžiku. Zahrnuje podrobnosti o účastnících, zprávy a stavy trasy.
  • vyberteIsConnectedToRoom: Balíček 100 ms poskytuje řadu selektorů, které můžeme použít k extrahování informací z obchodu. V tomto případě extrahujeme boolean hodnota, která vám řekne, zda jste připojeni k místnosti nebo ne.

O dalších selektorech si můžete přečíst zde.

V onMount nastavíme posluchač, který volá onRoomStateChange kdykoli se změní stav připojení. onRoomStateChange na to reaguje přesměrováním na příslušnou stránku na základě svého vstupu.

Přejděte na home.svelte soubor a nahraďte jeho obsah:

<script>
  import { hmsActions } from "./../services/hms";
  import { getToken } from "./../utils/utils";
  let userName = "";
  let role = "";

  const submitForm = async () => {
    if (!userName || !role) return;
    try {
      const authToken = await getToken(role, userName);
      const config = {
        userName,
        authToken,
        settings: {
          isAudioMuted: true,
          isVideoMuted: false,
        },
        rememberDeviceSelection: true,
      };
      hmsActions.join(config);
    } catch (error) {
      console.log("Token API Error", error);
    }
  };
</script>

<main>
  <form>
    <header>Join Room</header>
    <label for="username">
      Username
      <input
        bind:value={userName}
        id="username"
        type="text"
        placeholder="Username"
      />
    </label>
    <label>
      Role
      <select bind:value={role} name="role">
        <option value="speaker">Speaker</option>
        <option value="listener">Listener</option>
        <option value="moderator">Moderator</option>
      </select>
    </label>
    <button on:click|preventDefault={submitForm}> Join </button>
  </form>
</main>

Zde importujeme:

  • hmsActions: To se používá k provedení jakékoli akce, jako je připojení, ztlumení a odeslání zprávy.
  • getToken: Pomáhá nám to vygenerovat token, který potřebujeme k připojení k jakékoli 100ms místnosti.

Máme také funkci submitForm , který spojuje config proměnnou a přidá nás do místnosti pomocí hmsAction .

V označení si všimnete, že máme bind :ve vstupu. Tomu se říká směrnice a Svelte nám dává mnoho směrnic, které nám usnadňují život.

bind:value direktiva spojuje hodnotu vstupu se zadanou proměnnou.

Ve vašem případě je tato proměnná username variabilní. Můžete jej také použít v select živel. on:click direktiva na druhé straně připojuje zadanou funkci jako handler k události click na tomto tlačítku.

Svelte nám také poskytuje modifikátory jako |preventDefault který přizpůsobuje směrnici našemu vkusu. V našem případě |preventDefault volá event.preventDefault před spuštěním obslužné rutiny.

Také si všimnete, že jsme neimplementovali getToken funkce, tak pojďme na to. Vytvořte utils.js soubor v adresáři src/utils a vložte následující:

const TOKEN_ENDPOINT = process.env.TOKEN_ENDPOINT;
const ROOM_ID = process.env.ROOM_ID;

export const getToken = async (userRole, userName) => {
  const role = userRole.toLowerCase();
  const user_id = userName;
  const room_id = ROOM_ID;
  let payload = {
    user_id,
    role,
    room_id,
  };
  let url = `${TOKEN_ENDPOINT}api/token`;
  const response = await fetch(url, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify(payload),
  });
  let resp = await response.json();
  return resp.token;
};

Nejprve extrahujte proměnné prostředí z process.env . Poté zavolejte do koncového bodu, který vám byl poskytnut, do 100 ms. Tento koncový bod odpoví potřebným tokenem.

Ale nenastavili jsme naše environmentální proměnné. Můžeme to udělat snadno instalací některých balíčků. Běh

yarn -D dotenv @rollup/plugin-replace

abyste je nainstalovali. Poté otevřete soubor rollup.config.js v kořenovém adresáři složky a vložte následující:

//NEW LINE STARTS
import replace from "@rollup/plugin-replace";
import { config } from "dotenv";
//NEW LINE ENDS

const production = !process.env.ROLLUP_WATCH;

//CODE OMITTED FOR BREVITY

export default {
  input: "src/main.js",
  output: {
    sourcemap: true,
    format: "iife",
    name: "app",
    file: "public/build/bundle.js",
  },
  plugins: [
      //NEW LINE STARTS
    replace({
      "process.env.NODE_ENV": JSON.stringify("production"),
      "process.env.TOKEN_ENDPOINT": JSON.stringify(
        config().parsed?.TOKEN_ENDPOINT || process.env.TOKEN_ENDPOINT
      ),
      "process.env.ROOM_ID": JSON.stringify(
        config().parsed?.ROOM_ID || process.env.ROOM_ID
      ),
    }),
      //NEW LINE ENDS
    svelte({
      preprocess: preprocess(),
      compilerOptions: {
        dev: !production,
      },
    }),

Naše getToken funkce by nyní měla být spuštěna.
Dále nahraďte kód v room.svelte s následujícím:

<script>
  import page from "page";
  import Peer from "./../components/peer.svelte";
  import { hmsActions, hmsStore } from "./../services/hms";
  import { selectPeers,selectLocalPeerRole,
    selectIsLocalAudioEnabled, } from "@100mslive/hms-video-store";
  import { onMount, onDestroy } from "svelte";
  import { PeerStore } from "./../stores";

  let peers = [];
  let localPeerRole = "";
  let audioEnabled = null;

  const handlePeers = (iPeers) => {
    let res = hmsStore.getState(selectLocalPeerRole);
    localPeerRole = res ? res.name : "";
    audioEnabled = hmsStore.getState(selectIsLocalAudioEnabled);
    PeerStore.set(iPeers);
  };

  const handleMute = async () => {
    await hmsActions.setLocalAudioEnabled(!audioEnabled);
    audioEnabled = hmsStore.getState(selectIsLocalAudioEnabled);
  };

  onMount(async () => {
    hmsStore.subscribe(handlePeers, selectPeers);
  });

  const leaveRoom = () => hmsActions.leave();

  onDestroy(leaveRoom);

  $: peers = $PeerStore;
</script>

<main>
  <h1>Welcome To The Room</h1>

  <section class="peers">
    {#each peers as peer (peer.id)}
      <Peer {localPeerRole} {peer} />
    {/each}
  </section>
  <div class="buttons">
    {#if localPeerRole != "listener"}
      <button on:click={handleMute} class="mute"
        >{audioEnabled ? "Mute" : "Unmute"}</button
      >
    {/if}
    <button on:click={leaveRoom} class="leave">Leave Room</button>
  </div>
</main>

Tato stránka obsahuje nejdůležitější funkce naší aplikace. Nejprve naimportujeme požadované proměnné. Některé z nich jsou:

  • onDestroy: Tato funkce je podobná funkci onMount kromě toho, že je volána bezprostředně před odpojením komponenty.
  • PeerStore: Toto je obchod, který by sledoval aktuální vrstevníky v místnosti.

handlePeers Funkce dělá tři věci:

  • Ukládá roli místního partnera do localPeerRole proměnná.
  • Nastavuje stav zvuku místního partnera v audioEnabled proměnná.
  • Ukládá aktuální partnery v místnosti do PeerStore obchod.

handleMute funkce jednoduše přepíná stav zvuku místního partnera. A leaveRoom je voláno, když má být komponenta odpojena nebo když Leave Room klikněte na tlačítko.

$: syntaxe nám pomáhá vytvářet reaktivní příkazy. Tyto příkazy se spustí bezprostředně před aktualizací komponenty, kdykoli se změní hodnoty, na kterých závisí.

V našem značení máme 2 nové syntaxe:

  • {#each peers as peer (peer.id)} :To nám pomáhá zmapovat každého partnera v peers pole pomocí ID partnera jako klíče.
  • {#if localPeerRole != "listener"} :To vykreslí komponentu mezi if blok, pokud je podmínka pravdivá. Proto vykresluje Mute pokud místní partner není posluchač.

Na poslední komponentu, peer.svelte . Naposledy zkopírujte níže uvedený kód do souboru:

<script>
  import {
    selectIsPeerAudioEnabled,
  } from "@100mslive/hms-video-store";
  import { onMount } from "svelte";
  import { hmsActions, hmsStore } from "../services/hms";
  export let peer = null;
  export let localPeerRole = "";

  let isContextOpen = false;
  let firstCharInName = "";
  let isPeerMuted = false;

  const togglePeerAudio = () => {
    hmsActions.setRemoteTrackEnabled(peer.audioTrack, isPeerMuted);
  };

  const changeRole = (role) => {
    hmsActions.changeRole(peer.id, role, true);
  };

  onMount(async () => {
    hmsStore.subscribe((isPeerAudioEnabled) => {
      isPeerMuted = !isPeerAudioEnabled;
    }, selectIsPeerAudioEnabled(peer?.id));
  });

  $: firstCharInName = peer ? peer.name.split(" ")[0][0].toUpperCase() : "";
</script>

<div class="peer">
  <div on:click={() => (isContextOpen = !isContextOpen)} class="content">
    <div class="image">
      <p>{firstCharInName}</p>
    </div>
    <p>{peer ? peer.name : ""}{peer && peer.isLocal ? " (You)" : ""}</p>
  </div>
  {#if localPeerRole == "moderator" && !peer.isLocal}
    <div class="context" class:open={isContextOpen}>
      <button on:click={togglePeerAudio}
        >{isPeerMuted ? "Unmute" : "Mute"}</button
      >
      <button on:click={() => changeRole("speaker")}>Make Speaker</button>
      <button on:click={() => changeRole("listener")}>Make Listener</button>
    </div>
  {/if}
</div>

Opět jsou importovány všechny potřebné proměnné. Očekáváte 2 rekvizity:peer a localPeerRole .

Jsou deklarovány 2 funkce:togglePeerAudio a změnit roli . Dělají přesně to, co jejich jména popisují. V onMount funkce, je přidán obslužný program, který aktualizuje **isPeerMuted **stav peeru.

Každá peer komponenta má kontextovou nabídku, která má možnosti pro ztlumení peeru nebo změnu jeho role. Ale toto menu je dostupné pouze moderátorům, protože pouze oni by měli mít taková oprávnění.

V tuto chvíli jsme hotovi.

Můžete běžet

yarn dev

v terminálu pro zobrazení aplikace.

  • Vyplněnou přihlášku si můžete prohlédnout zde.
  • Zde můžete vidět kód GitHub pro aplikaci.