발표명: 묻고 한벌로 가! (네이버 플레이스 한 벌의 코드로 모바일 웹/모바일 앱/PC 웹 서비스 확장 개발기)
발표자: 윤영제 - 네이버 플레이스
요약
네이버 플레이스 서비스는 각 업종별로 커스터마이징된 템플릿을 가지고 정보를 제공해주고 있으며, 모바일 기준 통합 검색의 15% 를 담당하고 있다. 이 정보는 지도앱과 제공되는 부분이 겹치고 있어 통합이 필요한 상황이었다.
지도는 모바일앱, PC/모바일웹 서비스를 제공중이기 때문에 이에 따라 각 플랫폼 별 요구사항에 맞춰 서비스를 제공해 주어야 한다.
최대한 중복 코드를 줄이고 도메인별 운영 포인트를 줄이기 위해 했던 고민들에 대한 공유이다.
이슈
- 플레이스, 지도의 검색 결과가 동일하지 않은 이슈가 있음 -> 통합 필요
- 각 지도 서비스 플랫폼별로 노출 템플릿에 요구사항이 있음
- ex. 길찾기 버튼의 유무, 뒤로가기 버튼의 유무 등
모바일 앱 통합
요구사항
- 웹뷰로 제공해야 하며, 네이티브 <-> 플레이스 웹뷰간 데이터 통신이 필요하다
- 유저가 어색함을 느끼지 않을 정도의 퍼포먼스를 가져가야 한다
웹뷰의 적용 범위
장소 검색 결과 및 지도 내 마커 클릭 후 디테일 페이지는 플레이스가 가져간다
플레이스 내 서비스에서 지도 웹뷰 표기될 부분 분할
- 플레이스는 지도화면 + 업종정보로 나뉘어져있음
- 업종정보 부분 컨테이너만 떼어냄
- 지도웹뷰에서 해당 부분 노출
- 코드상 분기로 웹/지도앱 관련 특화 기능 버튼 노출
유저 검색 플로우
- 유저 검색 요청
- 지도앱에서 WebView URL 호출
- 플레이스 웹서버에서 SSR 결과 전송
- WebView 에 HTML load
- HTML load 완료 후 지도앱쪽에 메시지 전달
- 지도앱은 메시지를 전달받아서 필요한 작업(ex. 지도에 마커표시) 수행
WebView to Native
목적: 플레이스에서 노출된 결과를 지도 마커로 표기
aOS 앱스킴(inapp://)
주소 변경되는 경우 웹뷰에 영향을 주는 사이드이펙트가 있었음.
-> 보이지않는 iframe 을 만들어서 이 컴포넌트가 앱스킴 호출을 담당하는 것으로 처리하였다고 함
iOS webkit.messageHandler
스크롤할때마다 앱스킴 호출시에는 성능이슈가 발생해서 postMessage 로 통신하는 것으로 처리하였다고 함
Native to WebView
기본적으로는 웹뷰 url 호출
문제 : 호출할때마다 화면이 깜빡임
이유 : url 호출 -> 서버에 재호출 -> 서버가 데이터를 새로내려움 -> 깜-빡
의문 : 굳이 화면 요청할 필요없이 목록만 업데이트 하면 되는데?
해결 : 웹뷰레벨에서 사용할 수 있는 글로벌 함수를 플레이스쪽에서 만들어서, 신규 url 호출이 아니라 글로벌 함수 호출로 CSR 유도(로드된 페이지를 SPA식으로 재활용)
WebView, Native event handle
상황 : 앱 레이어가 지도레이어 위에 웹뷰가 깔리고, 웹뷰는 위 일정 height 가 투명이라 지도가 보이는 상태
문제 : 상단 레이어가 웹뷰라서 지도까지 터치이벤트가 안감
해결 : 웹뷰레이어 위에 투명 네이티브 레이어를 깔음 -> 앱이 먼저 터치이벤트 가져감
웹 통합
요구사항
- 지도 웹은 앵귤러이다
- 플레이스는 리액트이다
- 지도 웹안에 플레이스를 넣고싶다 -> iframe 활용
iframe 의 장단점
장점
- 영역이 완전히 분리/고립 됨 -> 크로스 프레임워크 조합으로도 서로에게 영향을 주지 않음
단점
- 보안 문제
- iframe url 은 바로 안보임
- 디버깅 어려움
유저 검색 플로우 (like app)
- 사용자가 검색
- iframe url 변경(로드)
- 플레이스 서버가 SSR
- iframe 의 HTML load
- iframe 에서 postMessage({action, data})
- 지도웹은 필요한 작업을 진행
통신방법 정의
여러가지 방법이 생기면 나중에 유지보수가 어려워지기 때문에 정립필요
- 지도 => 플레이스 : iframe url 변경으로만 사용
- 플레이스 => 지도 : postMessage({action, data})
모바일/웹 차이
- 가로 스크롤 : 좌우버튼 노출여부 등
- 세로 스크롤
- 모바일은 인피니티 스크롤
- PC 는 페이지네이션
- PC 의 마우스이벤트 처리 (mouseenter, mouseleave)
- PC 의 미지원이벤트 처리 (touchevent 로 발생하는 tooltip -> scroll 이벤트로 처리)
- 사소한 몇가지 컴포넌트의 분기
- 로그인이 필요한 경우
- iframe 이 부모창에 로그인 요청 -> 부모창에서 로그인시도 -> iframe 새로고침으로 로그인 쿠키반영
IE 11 폴리필 리서치
- polyfill.io(채택) : 필요한 폴리필들 가져와서 적용
- polyfill-library : 필요한 폴리필을 동적 판단. (대규모서비스에서의 퍼포먼스 고려하여 미채택)
- react-app-polyfill : 미지원 ES2016+ 문법 있음 (찾아내면서 개발하기 번거로워 미채택)
성능개선 포인트
이미지 사이징
- 노출사이즈에 맞게 썸네일 생성
- 썸네일의 퀄리티는 내리고 sharpen 값을 올리면 비슷한 품질에 용량을 크게 줄일 수 있음
초기로드 사이즈
- react-lazyload 로 렌더 퍼포먼스 최적화
- dynamic loading 으로 초기로드 에셋사이즈 줄임
로드 속도
- 유니버설 SSR 방식을 가졌는데 초기속도가 느린 이유의 리서치
- 현 상황에서 웹뷰 노출여부를 지도앱이 판단하는데, 이 지도앱은 웹뷰의 로드완료 메시지를 받아서 처리
- 메시지 송신 타이밍이 SSR + CSR => useEffect 라서 의미있는 첫 노출이 가능해도 웹뷰미노출
- SSR load 하자마자 지도앱에 메시지 전달하는 것으로 처리
- 사이드이펙트로 CSR 완료 전까지 유저인터렉션 불가능하나 사람이 인식하기 어려운 정도의 타이밍
기타
- 리액트 렌더링 최적화 : props 수정 필요한 부분에 커스텀훅으로 전달해서 불필요한 렌더 줄임
- 스크롤 최적화 : 전통적인 방식(onScroll + rect calc) => IntersectionObserver 사용
느낀점
개인적으로 앱-웹간 커플링이 심한 프로젝트의 투입이 예정되어있었는데, 우연히 좋은 영상을 보게되어서 이렇게 글을 쓰게 되었다.
플레이스에서 사용하는 스택은 사실상 내가(우리팀이) 선호하고 사용중인 스택과 거의 동일하다. 그래서 플레이스는 개인적으로도 좋아하는 곳이고 나중에 꼭 한번 가보고싶은 곳이기도 하다. 내가 원하는 개발환경과 비슷하기 때문이다.
실무에서 할 수 있는 트러블슈팅류의 내용을 이해하기 쉬운 정도로 잘라서, 많은 부분들을 보여준 좋은 영상이었다. 그리고 수많은 분기와 요구사항 변경으로 고통받았을 것이 느껴진다...
어디서 듣기로도 플레이스의 서비스가 굉장히 빡시다고 들었는데 영상에서 본 요구사항만 봐도 느껴진다..