React JS - Spiring Java 환경
어떤 라이브러리를 선택해야 할까?
기본적인 Websocket API
- html5 이전, 사파리, 파이어폭스 등 지원하지 않는 경우가 있다.
- 간단한 메시징이라면 사용해도 괜찮지만, 다양한 기능을 위해서는 다른 라이브러리 사용을 추천한다.
Socket.io 라이브러리
- Node.js 를 지원한다.
- 서버도 Socket.io 를 함께 사용해야 하기 때문에, Java Websocket 과는 호환되지 않는다.
SockJS-client 라이브러리 + STOMP.js
- Springframework 매뉴얼에서 SockJs 를 사용하여 웹소켓을 구현하기를 제시한다.
- 서버는 SplingFramework SockJS fallback 을 사용해 웹소켓을 구축하고
- 클라이언트는 SockJS 라이브러리를 사용해 구축된 웹소켓 서버에 연결하고, STOMP/stompjs 프로토콜 통신을 통해 실시간 메시지를 송수신한다.
- STOMP.js
- WebSocket 위에서 동작하며, 메시지 송수신을 보다 간편하게 처리할 수 있게 해준다.
- 구독, 발생, 헤더 인증
💡 SockJS 를 통해 소켓 통신을 연결하고, STOMP 를 통해 메시지를 송수신 합니다.
sockjs/socket-client
GitHub - sockjs/sockjs-client: WebSocket emulation - Javascript client
WebSocket emulation - Javascript client. Contribute to sockjs/sockjs-client development by creating an account on GitHub.
github.com
해당 라이브러리를 사용해서 코드에 적용하는데에 문제가 있었음.
🚨 Uncaught ReferenceError: global is not defined 에러 발생
위 에러는 스크립트에 직접 global 객체를 정의하라는 해결책이 구글링에 많았으나, 근본적인 해결책이 아니라고 생각했다.
global 은 Node.js 환경에서 사용할 수 있는 전역객체이다. 프로젝트는 react js 환경이기때문에 이 에러가 발생한 것으로 확인된다.
그럼 global 객체를 직접 정의하는 것은 적절한 해결 방법이 아니다.
💡 공식 깃허브 이뷰 439 에서 원인과 해결책을 확인할 수 있었다.
sockjs/socket-client 의 빌드 버전을 사용해야한다. dist 빌드파일을 임포트하여 해결했다.
`import sockjs from "sockjs-client/dist/sockjs"`
sockjs 를 호출할때 vscode 에서 자동 import 구문은 dist 버전이 아니었어서 놓친 것 같다.
공식문서를 꼼꼼히 확인하거나, 프로젝트 스펙과 유사한 깃허브 검색 및 탐방하는 경험이 문제해결에 큰 도움이 되었다.
STOMP.js
GitHub - stomp-js/stompjs: Javascript and Typescript Stomp client for Web browsers and node.js apps
Javascript and Typescript Stomp client for Web browsers and node.js apps - stomp-js/stompjs
github.com
sockjs 로 커넥션 생성 후, stompjs 의 client 로 STOMP 클라이언트 활성화
사용자의 채팅 리스트 구독, 채팅방 구독을 통해 요청이 있을 경우를 감지한다.
🚨 웹소켓 서버를 open 하는 적절한 위치
- 컴포넌트 렌더 : 하나의 페이지에서 웹소켓 서버 관리, 채팅리스트와 채팅창은 컴포넌트로 렌더
- 커스텀 hook 사용 : 각각 다른 서버에 연결할때 적절
- `Context API` : 다른 페이지, 하나의 웹소켓에 적절
다음 세 위치에서 관리할 수 있다.
캠퍼스 프로젝트는 navbar 의 채팅페이지 접속 시 채팅목록 표시, 리스트 클릭 시 chatId 채팅방 표시한다.
처음에 2. 커스텀 hook 을 이용하여 코드를 작성했다.
채팅 리스트 페이지와 채팅 룸 페이지가 각각 다른 웹소켓 서버를 연결하게 되는 문제가 발생
재사용성에 좋지만, 단일 서버 연결이어서 여러 부분이 동일한 서버에 연결해야 하는 경우에 적합하지 않았다.
- 3번 방식 `Context API` 를 사용하게 될 경우
전체 페이지에서 웹소켓 통신이 오픈 된 상태로 유지하게 되는 방식이다.
웹소켓을 통해 새로운 채팅 알림 수신은 웹소켓 서버 통신이다. 새로운 채팅이 생성되면 알림을 전달할 수 있어야 한다고 생각하여 전체 페이지에서 소켓통신을 열도록 개선했다.
그러나 백엔드에게 확인 결과, 추후 FCM 알림에 새로운 채팅 메시지 알림이 등록될 예정이라고 했다. 따라서 클라이언트 전역에서 웹소켓 통신을 오픈할 필요가 없는 문제가 발생했다.
- 1번 컴포넌트 렌더링 + 2번 커스텀 hook 을 사용하여 각각 다른 웹소켓 서버를 연결하는 문제를 해결할 수 있었다.
기존의 채팅목록, 채팅방 페이지는 컴포넌트로 이동했다.
chatPage 에서 선택한 chatRoomId, 웹소켓 서버를 관리하여 하나의 페이지에서 하나의 웹소켓 서버를 사용할 수 있도록 개선했다.
전역 페이지 코드에서 hook 을 통해 웹소켓 서버를 오픈하고, 웹소켓 통신의 hook 내부에서 수행했다.
프로젝트 전역 레이아웃 설정에 묶이지 않는다
관련 commit : https://github.com/IT-Cotato/10th-Kampus-FE/pull/118/commits/e5d29c26429bdb7361738fd7d5288d2af24c3351
컴포넌트 렌더링 방식에서, 프로젝트 전역에 설정한 레이아웃이 적용되는 문제 발생
채팅 목록 의 경우에 전역 레이아웃이 필요하고 채팅방의 경우 전역 레이아웃이 필요하지 않음
예외적으로 채팅 페이지 코드에서 ChatLayout 컴포넌트를 생성해여 navbar 렌더링 여부를 설정
✨ 배운 점
💡 다양한 방식 고민과 시도를 통한 문제 해결
문제상황 3. 웹소켓의 적절한 위치 에서 웹소켓을 구현할 수 있는 3가지 방식을 조사하고, 모든 방식을 구현해 보았다.
최종적으로 두가지 방식을 조합하여 문제를 해결했다.
이 과정에서 FCM 알림 시스템 등에 대해 조사하고, 동료 개발자들에게 질문하며 넓은 지식을 쌓을 수 있었다.
다양한 방식을 모두 시도해본것이 실패가 아닌, 다음 단계를 위한 발판이었음을 느꼈다.
앞으로도 넓은 시야로 미션을 점검하고, 주도적으로 역량을 펼쳐나갈 수 있게 되었다.
