Svelte+WebSocket으로 간단한 채팅 소프트웨어 만들기

Svelte와 웹소켓을 배우기 위해 메모로 요약한 간단한 채팅 앱을 만들었다.

기본적


Svelte란?


Svelte는 React 및 Vue입니다.js처럼 선언된 UI로 웹 응용 프로그램을 만드는 도구입니다.Vue.js의 SFC처럼 .svelte 파일에서 HTML, 자바스크립트, CSS를 단일 구성 요소로 관리하여 프로그램을 구성합니다.
React 및 Vuejs와 가장 큰 차이점은 프로그램 코드를 순수한 자바스크립트 파일로 미리 컴파일하여 클라이언트에서 로컬 DOM 스크립트로 실행하는 것이다.가상 DOM을 사용하지 않기 때문에 구축된 코드는 전용 운행 시간 라이브러리를 포함하지 않고 매우 가볍다.
https://svelte.dev/

WebSocket이란 무엇입니까?


WebSocket은 단일 TCP 연결에서 양방향 통신을 위한 통신 프로토콜입니다.WebSocket을 사용하면 통신이 이루어지면 일반적인 HTTP 통신으로는 불가능한 서버 시작점의 데이터를 보낼 수 있다.따라서 이전 pooling 등에서 이루어진 무중재 실시간 데이터 업데이트를 쉽게 실현할 수 있다.

https://livelibrary.osisoft.com/LiveLibrary/content/en/web-api-v8/GUID-EA5DCD55-A957-4B47-9556-22A7920BD82F#addHistory=true&filename=GUID-021731EE-C9B6-4236-9BE5-1ED92C43B319.xml&docid=GUID-EA5DCD55-A957-4B47-9556-22A7920BD82F&inner_id=&tid=&query=&scope=&resource=&toc=false&eventType=lcContent.loadDocGUID-EA5DCD55-A957-4B47-9556-22A7920BD82F

채팅 애플리케이션 만들기


우리는 다른 브라우저에서 열어도 실시간으로 동시 실행할 수 있는 채팅 소프트웨어를 만들었다.

소스 코드 여기 있습니다.
https://github.com/kawamataryo/svelte-simple-chat
아래의 요점만 기록하시오.

서버 측 설치


서버 측의 설치는 매우 간단하다.
Node.js에서 웹소켓을 처리하는 프로그램 라이브러리 ws 를 사용합니다.
https://github.com/websockets/ws
import WebSocket from "ws"

const wss = new WebSocket.Server({ port: 8082 });

type Chat = {
  userId: string,
  message: string
}

// インメモリでデータを保持
const chatBoard: Chat[] = [];

wss.on('connection', (ws) => {
  ws.on('message', (payload) => {
    if(typeof payload === 'string') {
      chatBoard.push(JSON.parse(payload));
    }

    // 全ての接続先に送信
    wss.clients.forEach((client) => {
      client.send(JSON.stringify(chatBoard));
    })
  });

  ws.send(JSON.stringify(chatBoard));
});
new WebSocket.Server에서 서버 실례를 만들고 wss.on('connect', callback)에서 웹소켓을 연결할 때 처리합니다.연결 시 호출 수신ws을 사용하고 ws.on('message', callback)에 요청을 받을 때의 처리가 적혀 있습니다.
요청을 받을 때 메모리에 저장된 채팅 메시지 배열의 업데이트와 동시에wss.clients 모든 연결 중인 고객을 얻고 각 고객에게 발송send된 새로운 채팅 메시지의 배열.ws.send를 사용할 경우 요청을 보낸 고객에게만 메시지를 보내고 다른 브라우저에서는 동기화할 수 없습니다. 주의하십시오.

클라이언트 측 설치


클라이언트 측은 Svelte의 Type Script 템플릿을 기반으로 채팅 앱을 제작하고 있다.
Type Script의 프로젝트 제작은 여기를 참조합니다.
https://svelte.dev/blog/svelte-and-typescript
구성 요소는 전체 보드 App.svelte 를 표시하고, 하나의 메시지 Message.svelte 를 표시하며, 메시지의 입력 형식 MessageForm.svelte 의 3개를 표시합니다.
우선Message.svelte.
Svelte의 Proops는 script 태그export의 변수입니다.이 구성 요소는 currentUserId, userId, message 세 개의 프로포즈를 수신하고 그 내용에 따라 정보를 표시한다.
이외에도 class:mine="{currentUserId === userId}"의 부분에서는current UserId와userId가 일치하는 경우에만classmine를 준다.
아바타 이미지는 Avatars의 문자열에서 아바타 이미지를 생성하는 API를 이용한다.
https://avatars.dicebear.com/
client/src/components/Message.svelte
<script lang="ts">
  export let currentUserId: string;
  export let userId: string;
  export let message: string;
</script>

<div class="message-container" class:mine="{currentUserId === userId}">
  <img width="40px" src="{`https://avatars.dicebear.com/api/bottts/` + userId + '.svg'}" alt="Avatar" />
  <div class="balloon">{message}</div>
</div>

<style>
/* ... */
</style>
다음은MessageForm.svelte.
이 구성 요소에서 부모 구성 요소에 클릭 이벤트를 보내기 위해 createEventDispatcher 발송 단추를 누르면submit 이벤트를 나누어 줍니다.createEventDispatcher와 Vue가 말한 emit는 같다.또한 부모 구성 요소에서 수신된message 프로포즈의 내용bind:value을 input 요소에 분배한다.MessageForm 어셈블리를 모 어셈블리에서 정의할 때bind:message 메시지의 변경 사항을 모 어셈블리에 투명하게 반영할 수 있습니다.
※ 양식 요소의 구성 요소 간 데이터 교환은 여기를 참조하십시오.
https://svelte.dev/tutorial/component-bindings
client/src/components/MessageForm.svelte
<script lang="ts">
  import { createEventDispatcher } from 'svelte';

  export let message;

  const dispatch = createEventDispatcher();
  const handleSubmit = () => {
    dispatch('submit');
  };
</script>

<input bind:value="{message}" class="input" type="text" placeholder="Your message" />
<button class="button is-link" on:click="{handleSubmit}">submit</button>
마지막App.svelte.
WebSocket 연결 및 메시지 수신 시 이벤트는 라이프 사이클 연결onMount에 정의되어 있습니다.메시지를 받을 때 내부에 저장된 활동 변수messages에 데이터를 대입하여 채팅 데이터의 업데이트를 진행한다.
또 웹소켓에 접속했을 때, 정보를 받았을 때의 처리를 socket.onopen·socket.onmessage에 로그인했다.정보를 받을 때JSON.parse로 수신 데이터messages를 지우고 대입합니다.
또한 handleSubmit 이 함수로 발송 단추를 누르면 웹소켓에 추가 정보를 보냅니다.먼저 업데이트messages의 값은 자신이 일으킨 데이터 업데이트가 웹소켓의 통신을 기다리지 않아도 반영되기 때문이다.
client/src/App.svelte
<script lang="ts">
  import { onMount, tick } from 'svelte';
  import Message from './components/Message.svelte';
  import MessageForm from './components/MessageForm.svelte';
  import { getUserId } from './lib/getUserId';

  let message = '';
  let messages: { userId: string; message: string }[] = [];
  let socket: null | WebSocket = null;
  let board: null | Element;

  const currentUserId = getUserId();

  const scrollToBottom = async () => {
    await tick();
    board.scrollTop = board.scrollHeight;
  };

  const handleSubmit = () => {
    if (!message) {
      return;
    }
    messages = [...messages, { userId: currentUserId, message }];
    socket.send(JSON.stringify({ userId: currentUserId, message }));
    message = '';
    scrollToBottom();
  };

  onMount(() => {
    socket = new WebSocket('ws://localhost:8082');
    socket.onopen = () => {
      console.log('socket connected');
    };
    socket.onmessage = (event) => {
      if(!event.data) { return }
      messages = JSON.parse(event.data);
      scrollToBottom();
    };
  });
</script>

<main>
  <div class="wrapper">
    <h1>Svelte simple chat</h1>
    <div class="board" bind:this="{board}">
      {#each messages as { userId, message: mg }}
        <Message currentUserId="{currentUserId}" userId="{userId}" message="{mg}" />
      {/each}
    </div>
    <div class="message-form-wrapper">
      <MessageForm bind:message on:submit="{handleSubmit}" />
    </div>
  </div>
</main>

<style>
/* ... */
</style>

참고 자료

  • https://zenn.dev/toshitoma/articles/what-is-svelte
  • https://svelte.dev/
  • https://www.codegrid.net/articles/2020-svelte-1/
  • https://ja.wikipedia.org/wiki/WebSocket
  • http://wild-data-chase.com/index.php/2019/03/17/post-630/#outline__4
  • https://www.html5rocks.com/ja/tutorials/websockets/basics/
  • 끝맺다


    이상은'Svelte+WebSocket 만들기 간단한 채팅 앱'이다.
    Svelte와 웹소켓은 모두 촉감적이지만 의외로 사용하기 쉽다.나는 다시 한번 기회를 보고 쓰고 싶다.

    좋은 웹페이지 즐겨찾기