Design
여기쏙 — Figma plugin 제작기 : 2. UI
임수빈Melody(멜로디) / 서비스웹개발팀여기어때
2025년 12월 9일
원문에서 보기 ↗안녕하세요, 서비스웹개발팀의 멜로디입니다!
지난 글에서는 Figma 플러그인 ‘여기쏙’이 실제 데이터를 사용할 수 있도록 프록시 서버를 구축한 과정 을 소개했어요. 이번 글에서는 이 프록시 서버와 연동해, 플러그인에서 실데이터를 어떻게 받아와 적용했는지 이야기를 이어가 보려고 합니다.

개발 전 UX 점검
개발을 시작하기 전에, 플러그인의 사용 흐름과 플로우를 먼저 점검하는 과정 이 필요했어요. 실제로 기획된 시나리오를 따라가 보니 일부 UX가 실제 작업 방식과 맞지 않는 부분들이 있었고, 특히 ‘최근 사용’ 기능에서 무엇의 최근 사용을 의미하는지 모호한 워딩 이 사용자에게 혼란을 줄 수 있다는 점을 발견했어요. 또 제휴점 리스트를 불러올 때 여러 항목이 한 번에 저장되지만, 매번 갱신되는 구조가 PLP 화면에서는 오히려 불필요한 정보로 보일 수 있다는 문제 도 있었어요. 이런 지점들을 개발자 관점이 아니라 사용자의 맥락에서 이해하기 어려운 부분들로 정리해 팀에 공유했고, 디자이너와 함께 논의하며
- 워딩을 더 명확하게 다듬고
- 최근 사용 정보는 실제로 필요한 화면에서만 노출하도록 플로우를 조정
하는 등 여러 UX 개선을 진행할 수 있었어요. 작은 수정들이었지만, 직접 UX 개선에 참여하면서 “아, 나는 UX에 정말 관심이 많구나”라는 걸 다시 한 번 느낀 과정이었어요

UX를 정비 후, 기술 구조를 고민하기
사용 흐름을 명확하게 정리한 뒤에야, 이 플러그인을 어떤 기술 구조로 구현할지 고민할 수 있었어요. 왜냐하면 Figma 플러그인은 일반 웹 서비스와 달리 Figma 내부에서 작게 동작하는 도구이기 때문이에요. 성능적인 제약도 있고, 과도한 리소스를 사용하는 구조는 적합하지 않죠. 그래서 다음과 같은 기준으로 기술 스펙을 설계했어요.
- 리소스를 최소화하고
- 빠르게 로딩되며
- 유지보수 비용이 낮고
- 확장 가능한 구조
즉, 플러그인 환경에서 가장 잘 동작할 수 있는 가볍고 단순한 구조를 선택하는 것이 핵심이었어요.
최대한 가볍게 기술 스펙 구성하기
여기쏙 플러그인은 Figma 안에서 WebView로 실행되는 작은 도구 이기 때문에 로딩 속도, 번들 크기, 유지보수 난이도를 모두 고려해 가볍고 단순한 기술 조합으로 구성했어요.
1) React 대신 Preact 선택
- Figma 플러그인은 웹뷰 하나에서 돌아가기 때문에 로딩 속도가 매우 중요
- 번들 크기가 훨씬 작아 플러그인 환경(사이즈 제한 + 빠른 로드 필요)에 최적.
- React와 거의 동일한 API → 학습 부담 없음.
2) 상태관리 Signals (@preact/signals)
- Redux, Zustand 같은 대형 스토어를 쓰기엔 플러그인 규모가 작음
- Signals는 작고 빠르고 직관적
3) React Query는 필요한 부분에만
- API 요청 캐싱 & 로딩 처리만 담당
- 무거운 글로벌 상태관리 대신 “데이터 fetching”만 맡김
- 프록시 호출 결과를 재활용해 네트워크 비용도 아낌
마침 팀에서 @tanstack/react-query 스터디를 진행하고 있어서 도움이 많이 되었어요.
4) 스타일은 goober로 최소화
- 플러그인은 CSS-in-JS를 쓰지 않으면 컴포넌트 단위 스타일 관리가 불편
- styled-components는 너무 무거움
- 빠른 스타일링 + props 기반 동적 스타일 지원
5) create-figma-plugin 생태계를 그대로 사용
- Figma 플러그인 개발 표준 템플릿.
- 번들링/타입 정의/UI ↔ Plugin 스레드 브릿지까지 기본 제공 → 초기 세팅 비용 거의 없음.

페이지 구성
플러그인의 기본 레이아웃을 가장 먼저 만들었어요. 그다음, 화면 전환 구조를 어떻게 설계할지 고민하면서 지역 × 페이지 유형 기반의 미니 라우터를 구성했습니다.
여기쏙은 URL 라우팅이 필요한 웹서비스가 아니라, 상태만으로 화면을 전환하면 충분한 플러그인 UI 예요. URL 네비게이션이나 브라우저 히스토리 관리가 필요하지 않기 때문에 굳이 react-router 같은 외부 라우터를 사용할 필요가 없었어요.
여기쏙 2.0의 화면은 크게 두 개의 축으로 나뉩니다.
- 상단 탭: 국내 / 해외 (Region)
- 하단 탭: PLP / SRP / PDP / ILP (PageType)

이 두 값을 조합해"DOMESTIC:PLP", "OVERSEAS:PDP" 같은 페이지 ID 를 만들고,이 페이지 ID를 기준으로 어떤 화면을 렌더링할지 결정하는 간단한 미니 라우팅 구조로 설계했어요.
1. ALL_PAGES — 페이지 정의 테이블

여기쏙 2.0의 페이지는 “국내/해외 + 페이지 타입” 조합으로 구분돼요. 그래서 각 페이지를 id와 실제 컴포넌트로 묶어 한 테이블에 모아두었습니다. 페이지 추가 시 이 배열에 한 줄만 더 넣으면 구조가 자동 반영되어 유지보수가 쉬워요.
2. activeId — 현재 활성 페이지 ID 계산
const activeId = (region: Region, page: PageType): PageId =>
`${region}:${page}` as PageId;
- 상단 Region 탭, 하단 PageType 탭을 조합해
"DOMESTIC:PLP"같은 페이지 ID를 만들어내요. - Signals store인
region.value,pageType.value값을 읽어 현재 활성 페이지를 판단합니다.
3. PageOutlet — 모든 페이지를 항상 마운트, 보여주기만 토글

왜 항상 마운트(Always-Mount) 방식을 선택했을까?
플러그인의 UI 구조를 설계하면서 고민했던 부분이 바로 렌더링 부분이었어요. ReactRouter 같은 “진짜 라우팅”을 쓰면 페이지 전환마다 언마운트가 발생하고, 반대로 하나의 상태로 페이지를 바꾸는 구조이면 페이지 상태 관리가 필요해져요. 결국 여기쏙에서는 다음 이유로 항상 마운트 방식을 선택했습니다.
1. 페이지 상태가 그대로 유지됨
페이지가 언마운트되지 않으므로 상태를 저장하는 store를 별도로 만들 필요가 없어서 훨씬 단순합니다.
- React Query 캐시
- 필터 값
- 스크롤 위치
- 내부 Signal 상태
- 모두 손대지 않아도 보존
2. 플러그인 UI 특성에 딱 맞음
Figma 플러그인은 작은 화면 안에서 여러 화면을 빠르게 넘나듭니다. 이때 페이지가 초기화되면 UX가 매우 안 좋아져요. Always-Mount는 탭 이동 → 즉시 화면 전환이 가능해 플러그인 UX에 아주 적합한 방식이에요.
3. 성능 부담 없음
각 페이지는 가벼운 구성이고, 복잡한 대형 UI나 리스트가 없기 때문에 모든 페이지를 마운트해두어도 성능에 문제 없다고 판단했어요.
이제 레이아웃을 구성했고, 이제 남은 건 컴포넌트 제작과 API 연동, 그리고 디자인 적용 단계 였어요. 그 전에 가장 먼저 정리해야 했던 것이 바로, “Figma 플러그인은 어떻게 동작하는가?” 였습니다. 플러그인은 일반 웹앱과 달리 내부 구조가 UI / Main 두 개의 프로세스로 나뉘어 있기 때문이에요.
Figma 플러그인은 두 개의 프로세스로 동작
1. UI Process — 화면을 담당하는 영역
우리가 만드는 플러그인의 UI(HTML/JS) 가 돌아가는 공간이에요. Figma 내부 DOM이 아닌 독립된 iframe(WebView) 에서 실행돼요. 그래서 Figma 문서를 직접 수정할 수 없고 , 네트워크 요청 시 origin이 null이라 CORS 문제도 쉽게 발생해요.
2. Main Process — Figma 문서를 다루는 영역
실제로 Figma 문서(노드)를 읽고 수정하는 역할이에요. figma.currentPage, figma.createNode() 같은 Figma API는 모두 여기서만 사용 가능합니다. UI에서 “노드 만들어줘!”라고 말하면 Main이 처리해주는 구조예요.
3. IPC — 두 영역이 대화하는 방법
UI와 Main은 서로 직접 접근할 수 없어요. 그래서 메시지를 주고받는 방식(postMessage) 으로만 통신합니다.
UI → Main: parent.postMessage()Main → UI: figma.ui.postMessage()
여기까지가 플러그인이 동작하는 기본 구조 이고, 이 부분은 다음 편에서 더 깊이 다룰 예정이에요. 이제 본격적으로 UI를 어떻게 구성했는지 이야기해보려고 합니다.
피그마 플러그인 UI Part
UI 필터 구조 설계
여기쏙의 PLP/SRP/PDP 등 모든 탭은 기본적으로 필터 기반 UI로 이루어져 있어요. 사용자가 조건을 설정하면, 그 값을 기반으로 API 요청 파라미터가 만들어지고, 조회된 결과가 Figma 디자인에 적용되는 흐름입니다.
그래서 가장 먼저 했던 작업은 필터 상태를 한 곳에 모아 관리할 구조를 만드는 것이었어요.
- 필터 UI
- API 요청 파라미터
- 최근 검색 저장
이 모든 로직이 하나의 상태(ex.PLPFilterState)에서 파생되도록 설계했습니다. 필터 항목이 늘어나더라도 타입만 확장하면 되기 때문에 유지보수도 편해요.

실제 서비스의 필터 폼 구조에서 필요한 부분을 그대로 가져와서 설계했어요.
category: 모텔/호텔/펜션/…areaId,subAreaId: 지역 대·소분류nights,personal: 숙박 박수, 인원sortType: 추천순, 거리순…priceRange: 1박 가격filters,grades: 할인 유형/숙소 등급
서비스 검색 로직과 동일하게 가져오면 디자인 화면도 실제 서비스와 더 정확하게 매칭될 수 있습니다.
서버 데이터 기반 동적 필터
지역 목록과 필터 옵션은 API 데이터로 동적으로 바뀌기 때문에 React Query + emitPromise 조합으로 처리했어요.
지역 목록 API

PLP 화면이 활성 상태 일 때만 호출되도록 enabled 조건을 걸고 데이터가 거의 변하지 않는 영역이므로 staleTime / gcTime = Infinity로 캐싱했어요. (플러그인 실행 시 딱 한 번만 호출) 옵션 변환도 간단합니다.
API 호출 — “적용 버튼” 기반 수동 트리거
필터가 바뀔 때마다 즉시 API를 호출하면 너무 비효율적이기 때문에, React Query를 enabled: false로 설정해두고 → “적용” 버튼이 눌릴 때만 refetch()를 수행하도록 했어요.

캐시 먼저 확인하기

같은 필터 조건으로 검색하면 API 호출 없이 React Query 캐시를 바로 재사용합니다.
API 호출 후 Figma Main으로 데이터 전달

UI → Main으로 데이터를 보내고 Main 프로세스에서 Figma 문서를 업데이트하는 구조예요. 플러그인 화면은 아래처럼 감싸서 구성했습니다.

- onReset → 모든 필터 초기화
- onApply → 캐시 확인 → API 호출 → Figma 적용
상용 API를 불필요하게 자주 호출하는 것은 낭비라고 판단했고, 여기쏙에서 사용하는 데이터는 실시간 최신성이 크게 중요한 영역도 아니었어요. 그래서 가능한 한 캐시를 적극적으로 활용해 API 호출 횟수를 최소화하는 방향으로 설계를 잡았습니다. 같은 조건으로 검색할 때는 기존 캐시를 바로 재사용해 훨씬 빠르게 결과를 보여줄 수 있었고, 플러그인 환경에서도 네트워크 리소스를 아끼면서 가볍게 동작할 수 있었어요.
또 하나 고려했던 부분은 캐싱을 프록시 서버 레벨에서도 적용할 수 있을지에 대한 고민이었어요. 플러그인 내부 캐시뿐 아니라 프록시에서 반복 호출되는 API를 적절히 캐시한다면, 전체적인 트래픽을 더 줄이고 서버 단에서도 성능을 개선할 여지가 있다고 판단했어요. 아직 바로 적용하진 않았지만, 추후 구조를 확장할 때 충분히 시도해볼 만한 방향이라고 생각합니다.
기능을 넘어서: UX까지 책임지는 개발자를 꿈꾸며
프로젝트를 진행하며 더 확실해진 것은 UX에 대한 애정이에요. 단순히 “작동하는 기능을 만드는 개발자”가 아니라, 사용자의 워크플로우를 이해하고, 문제를 발견하고, UI·UX 흐름 전체를 설계하는 개발자가 되고 싶어졌어요. 특히 이번 작업은, 디자이너가 실제 데이터를 기반으로 작업할 수 있도록 하고 반복적이고 번거로운 작업들을 자동화하며플러그인이라는 제한된 환경 속에서 최적의 UX를 만들기 위해 기획·디자인·개발의 교차지점을 직접 탐구하는 경험이었어요. 앞으로도 저는,기획 + 디자인 + 개발을 연결하는 UX 친화적 개발자로 성장하고 싶어요. 사용자 흐름을 세심하게 바라보고, 문제를 기능에서 끝내지 않고 UX 레벨에서 해결하고, 팀의 전체 경험 품질을 끌어올리는 개발자가 되고 싶어요.
여기까지가 제가 담당했던 아키텍처 개선과 성능 최적화, 그리고 플러그인 구조를 재정비한 이야기였습니다. 다음 편에서는 함께 작업한 제티가 여기쏙을 더 나은 도구로 만들기 위해 어떤 개발 개선을 진행했는지 이어서 풀어보려 합니다.