Index
안녕하세요, 저는 라포랩스 Frontend Engineer 이재은입니다.
이 글에서는 제가 Frontend Platform Team에서 진행했던 queenit-ui 라이브러리 제작한 경험을 공유합니다. 기존에 서비스에서 사용되는 이미지 애셋들을 Figma에서 직접 다운받아 저장하고, 프로젝트 내에서 관리하는 데 구성원들이 적지 않은 리소스를 쓰고 있었는데, 이를 자동화하여 팀의 생산성을 높이는 자동화 라이브러리를 개발하였습니다. 비슷한 문제로 골머리를 앓고 있는 분들께 글이 조금이나마 도움이 되길 바랍니다.
기존 이미지 관리 방식의 문제점 ![](data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==)
퀸잇에서 사용되는 이미지 애셋의 관리 방식은 기존에 Frontend와 Design Chapter의 가장 큰 부채 중 하나였습니다. 라포랩스에서는 기존 방식에 어떠한 문제점이 있었고 어떠한 방식으로 이 문제를 해결했는지 같이 여정을 떠나볼까요?
1. 중구난방 개명 당하고, 복제 되는 이미지들
기존에 저희 조직에서는 프론트엔드 개발자가 UI를 개발할 때 Figma에 등록된 이미지 애셋을 프로젝트에 추가하여 사용하는 방식이 큰 틀에서는 동일했지만, 개발자의 자유에 맡겨지는 부분이 있었습니다. 그 자유로 인해서 개발, 디자인 조직이 점점 커지면서 문제점들이 수면 위로 드러나게 되었습니다.
제가 최근에 개발한 출석체크 페이지를 예로 들어보겠습니다.
디자인 시안 속에서 사용하는 이미지는 총 5가지가 있습니다. 기존에 사용하고 있어서 프로젝트에 이미 존재하는 아이콘도 있고 (
/
/
번), 출석체크 피처로 인해서 새롭게 추가되어야 하는 이미지(
/
번)들이 섞여있습니다. 보통 개발자는 UI를 개발할 때, 새롭게 추가되는 이미지와, 기존에 존재해서 추가 저장이 필요없는 이미지를 구분하는 작업을 해야합니다.
그런데 새롭게 추가되어 프로젝트에 저장해야 하는 이미지와 그렇지 않은 이미지를 판별하는 일이 쉽지 않았습니다. 그 이유는 Figma에서 사용하는 이미지의 이름과 소스 코드에서 사용하고 있는 이미지 파일명이 다른 경우가 많았기 때문입니다. 디자인 시스템 상에서도 이미지를 관리할 때, 이름을 unique하게 지정하도록 강제하고 있지 않아서 비슷한 이미지 파일들의 이름 중복 문제도 있었고, 개발자가 자체적으로 더 좋다고 판단되는 이름을 붙여준 경우도 있었기 때문에 Figma에 등록된 이미지의 이름만으로 소스 코드를 검색해서 이 이미지가 사용되고 있는지 없는지 개발자가 판별하기는 어려웠던 것이죠. 이러한 이유로 퀸잇에서 자주 사용되는
번의 arrow_down 아이콘만 하더라도 프로젝트에서 같은 이미지 파일이 3개나 저장이 되어있는 상태였습니다. (IcArrowDown.tsx, ic_arrow_down_24.png, ic_bottom_lotus.svg 등)
이런 상황 속에서 프로젝트는 점점 커지면서 이미지 애셋을 관리하기가 점점 어려워졌고, 디자이너와 개발자의 커뮤니케이션 비용도 점점 늘어나게 되었습니다. 특히, 디자이너가 여러 곳에서 공통적으로 쓰이는 아이콘을 교체하고 싶어질 때, 해당 이미지가 어디서 쓰이는지 찾아서 한번에 교체하는 작업의 공수는 무척 커진 상황이었습니다. 더군다나 퀸잇의 경우, 프로덕트가 두 개가 있고(앱과 모바일 웹) 프로젝트 폴더도 두 개로 나뉘어 있어서 “이미지 교체”라는 가벼운 요청 사항이 결코 가볍게는 느껴지지 않게 되었습니다.
2. 귀찮고, 귀찮고, 귀찮은 개발자의 이미지 다운로드 반복 작업
사실 1번도 큰 문제였지만, 기존 이미지 관리 방식의 가장 큰 pain point는 Figma에서 이미지를 다운받아서 프로젝트에 저장하는 것 자체였습니다.
퀸잇 앱 React Native 프로젝트의 경우에는 1배, 2배, 3배의 png 파일들을 모두 다운받아서 프로젝트 내 저장하고 사용하고 있었고, Nextjs로 개발한 모바일웹 프로젝트는 svg와 png를 필요에 따라 적절히 다운 받아 사용하고 있었습니다. Feature가 크면 클 수록, 추가되는 이미지 애셋이 많으면 많아질 수록, 이 단순 반복 작업이 귀찮게 느껴졌습니다.
그래서 라포랩스에서는 이미지 관리 및 교체를 효율적으로 처리할 수 있는 새로운 자동화 된 관리 방식을 도입을 하기로 하습니다. 이를 통해 이미지 애셋 관리 방식을 재정비하고, 곧 예정된 디자인 시스템 라이브러리화 작업을 할 수 있는 기반을 마련하고자 했습니다. 그 결과로 탄생한 것이 queenit-ui입니다.
queenit-ui의 탄생 ![](data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==)
새로운 시스템의 요구사항
새로운 시스템은 위에서 언급한 문제들을 해결하기 위해, 다음과 같은 요구사항을 만족해야했습니다.
1.
이미지에 대한 변경사항이 있거나 추가가 필요할 때, 디자인 팀과 개발 팀의 커뮤니케이션 비용을 줄여줄 것
현재 디자인 팀 - 개발 팀의 통일되지 않은 이미지 이름 사용으로 인해서 커뮤니케이션 비용이 늘어났고, 이미지에 수정사항이 생겼을 때, 이미지의 사용처 트래킹이 어려워서 작업 공수가 많이 커졌음
2.
개발자가 이미지 파일을 Figma에서 직접 다운 받고, 프로젝트에 저장하는 공수를 줄여줄 것
퀸잇 앱의 경우에는 1배,2배,3배로 된 png 파일을 모두 다운 받아서 저장하고, 모바일 웹은 svg 혹은 png를 직접 다운받아서 사용해야했는데, 이런 반복적이고 귀찮은 일을 자동화하고자 함
3.
새로운 시스템으로 이미지 뿐만 아니라 색상, 디자인 시스템에 정의된 공통 UI 컴포넌트들도 관리될 수 있도록 확장 가능성이 있을 것
궁극적으로는 퀸잇 디자인 시스템을 라이브러리화 하고자 하는 장기적인 목표에 이 이미지 애셋 관리 방식이 시작점을 마련하고자 함. 그리고 그 방식은 React Native와 Next.js 에서 둘다 사용할 수 있는 방식이어야 함.
그리하여 위 사진에서와 같이, 디자인 팀에서 정리해 둔 Figma의 이미지 애셋들을 자동으로 읽어들여 라이브러리화하고, 앱과 모바일 웹 프로젝트에서는 그대로 그 라이브러리 설치하여 이미지들을 꺼내서 사용하는 형태의 자동화된 시스템을 제공해서 요구사항을 충족시킬 수 있다고 생각했습니다. 그리고 이러한 자동화된 시스템을 만들기 위해 개발팀과 디자인팀 모두의 협력이 필요했습니다.
유사한 문제를 해결하는 Figma 플러그인의 발견
이러한 시스템 구축을 하기에 앞서 가장 먼저 했던 것은 다른 곳에서 이미 이러한 시스템을 구축해놓지는 않았는지 찾아보는 일 (날로 먹을 수 있는 방법을 찾아보는 일)이었습니다. 이미 존재하는 것이 있다면 잘 가져다 쓰기만 한다면 비교적 쉽게 문제를 해결할 수 있었기 때문이죠.
구글링 끝에 저희의 요구사항을 100% 만족시켜주는 것은 찾지 못했지만, 아주 유사한 문제를 해결하는 Figma 플러그인을 발견하였습니다.
위에 첨부한 Figma 플러그인과 Github 프로젝트를 활용하면, 지정된 Figma 파일에서 정의된 아이콘 (svg) 을 모두 읽어들여, npm 패키지화 해주는 것이었습니다. 이미지를 사용할 React 프로젝트에서는 npm 패키지를 설치하고, 아이콘을 React 컴포넌트처럼 바로 사용할 수 있었습니다.
타겟으로 지정해준 Github Repository에 버전을 올려주는 역할만 담당하는 figma-icon-automation 플러그인
물론, 퀸잇 프로젝트에서 이미지를 사용하는 방식과는 다른 부분이 많아서 코드를 그대로 사용할 순 없었지만, 비슷한 플로우를 채택하여 개발에 착수하였고, figma-icon-automation 라이브러리가 제공해주는 Figma 플러그인은 그대로 활용하기로 했습니다. Figma 플러그인 자체는 타겟으로 지정해준 Github repository의 패키지 버전을 올려주는 역할만 하고 있었기에, 이 플러그인은 그대로 사용해도 무방하다고 판단했습니다.
새로운 시스템의 Flowchart
그래서 도입하게 된 새로운 이미지 애셋 관리방식은 위와 같은 플로우로 동작하게 되었습니다.
a.
(Designer
) 퀸잇 앱과 모바일 웹에서 사용되는 모든 이미지 애셋이 모여 있는 Figma 파일이 존재한다는 가정 하에, 이미지가 추가/수정되어야 할 때 해당 파일에서 작업을 합니다. 저희 조직의 경우에는 export의 대상이 되는 이미지 애셋들은 Figma Instance로 생성하여, 라이브러리가 export 되어야 할 Figma 요소와 그렇지 않은 요소를 구별할 때 그 요소가 Figma Instance인지 여부로 구분하기로 했습니다.
예를 들면, 실제 Figma 파일에서 export 되어야 하는 아이콘을 구분하기 위해 초록색으로 표시되는 아이콘들만 Figma Instance로 생성되고, 파일에서 아이콘들을 구분하기 위해 만들어진 나머지 부분들 (붉은색 눈금으로 표시된 문구나 도형)은 Instance화 하지 않도록 디자인팀과 규칙을 정하였습니다.
b.
(Designer
) 이미지가 추가/수정된 후에는 해당 변경사항을 반영하려면 Figma 플러그인을 통해서 버전을 올리고, 어떤 변경이 있었는지 설명란에 쓰게 됩니다. 플러그인에서 [push To Github] 버튼을 누르면 저희의 타겟 repository인 queenit-ui pull request(PR)가 올라갑니다. 해당 플러그인은 위에서 언급한 Figma 플러그인을 그대로 사용합니다. 여기서 플러그인의 역할은 입력받은 타겟 repository에, 입력받은 버전으로 repository의 패키지 버전을 올리는 역할 그 뿐입니다. 그 외의 모든 기능은 queenit-ui 내에서 처리합니다.
c.
(queenit-ui) 2번에서 queenit-ui에 PR이 올라가면, 개발자는 어떤 변경사항이 있었는지 PR 설명란을 통해 확인할 수 있습니다. PR이 open 시점에 Github Action이 트리거 되도록 설정하여서, 라이브러리를 배포하기 이전에도, 개발자가 해당 라이브러리를 테스트해 볼 수 있는 임시 버전이 생성됩니다.
개발자는 PR을 머지하여 라이브러리 정식 버전하기 전에, 임시 패키지를 통해서 새로운 애셋을 테스트할 수 있습니다.
d.
(FE
) 개발자는 3번에서 올라온 PR을 확인하고, PR에 comment로 달리는 라이브러리의 테스트 버전으로 새로 추가된 이미지가 문제없는 지 확인한 후에, PR을 머지합니다.
e.
(queenit-ui) PR이 머지될 때 실행되는 Github Action에서는, Figma에 등록된 모든 이미지들을 불러와서, 결국에는 저희의 end feature인 queenit-ui Github package로 배포하는 일까지 진행됩니다. queenit-ui 라이브러리 배포가 일어나기까지, 어떤 script들이 돌아가는지에 대해서는 뒤에서 더 자세히 다룰 예정입니다.
f.
(FE
) 라이브러리 배포가 성공하면 Slack으로 새로운 버전이 배포되었다는 알림이 전송되고, 개발자는 새로운 버전으로 패키지를 설치하여 프로젝트에서 이미지를 사용할 수 있습니다. 퀸잇의 경우, React Native로 개발된 앱과 NextJS로 개발된 모바일 웹 (및 웹뷰)이 모두 존재하기 때문에, 같은 이미지를 사용하더라도 import 하는 방식이 서로 다르고, 하나의 라이브러리에서 모든 이미지 파일을 가지고 있을 필요가 없다고 판단하여, 각각 필요한 형태의 이미지만 export되는 2개의 독립적인 패키지가 배포되도록 하였습니다.
라이브러리 버전 배포가 성공하면 Slack으로 알림이 갑니다
•
queenit-app-ui: queenit-react-native (퀸잇 앱을 위한 repository) 에서 사용
◦
React Native에서는 이미지를 import할 때, 1배,2배,3배의 png 이미지를 모두 갖고 있으면 해상도에 맞게 적합한 배율의 이미지 파일을 사용합니다.
◦
이미지의 이름은 apple.png, apple@2x.png, apple@3x.png 와 같은 형태로 되어야합니다.
•
queenit-web-ui: queenit-customer-web (퀸잇 모바일 웹, 웹뷰를 위한 repository) 에서 사용
◦
NextJS 프로젝트에서는 svg 아이콘으로 이미지를 사용하고 있는 경우도 있고 png 이미지를 사용하고 있는 경우도 있어서 둘 다 제공합니다.
◦
png의 경우 1배, 2배, 3배 모두 제공하여 개발자가 개발할 때, 적절한 배율의 이미지를 선택하도록 합니다.
◦
svg의 경우에는 원격 리소스가 아니라, inline element로 들어갈 수 있도록 React Component로 변환하고, 추가적으로 props로 color string을 받아 사용처에서 색상을 customize할 수 있도록 제공합니다.
queenit-ui repository 톺아보기
그렇다면 실제 5번 과정에서 PR이 머지된 후에, Figma 파일 속 이미지들을 fetch해서 저희 프로젝트에서 사용될 수 있는 형태로 패키지가 배포되는 과정까지 queenit-ui 에서 어떠한 일이 벌어지는지 샅샅이 파헤쳐보도록 하겠습니다.
queenit-ui의 간략한 folder structure
queenit-ui는 npm workspaces 로 구성한 monorepo입니다. 하나의 repository에서 queenit-react-native와 queenit-customer-web에서 사용될 패키지를 각각 따로 배포해야하기 때문에, monorepo로 구성하였습니다. 사실 패키지 자체는 복잡한 기능이 없고, 대부분의 script 코드는 공유가 되며, Figma에서 읽어들인 데이터를 후처리된 형태로 export해주는 코드만 있었기에 monorepo의 가장 간단한 기능만을 사용하기에는 npm workspaces가 적합하다고 판단했습니다.
PR이 머지가 되어 버전이 업데이트가 되면 다음과 같이 Github Action이 실행이 됩니다. 표시한 script가 단계별로 어떠한 작업을 담당하는 알아보겠습니다.
- name: Install dependencies
run: npm install
# 1️⃣ 번
- name: Synchronize queenit-app-ui & queenit-web-ui
version with the root package version
run: npm run sync-version
# 2️⃣ 번
- name: Fetch Figma assets from Figma file
run: npm run fetch
# 3️⃣ 번
- name: Export fetched assets in queenit-app-ui & queenit-web-ui
run: npm run export
# 4️⃣ 번
- name: Build queenit-app-ui & queenit-web-ui
run: npm run build
- name: Setup .npmrc file
run: |
echo "@rapportlabs:registry=https://npm.pkg.github.com/" > .npmrc
echo "//npm.pkg.github.com/:_authToken=${{ secrets.GH_TOKEN }}" >> .npmrc
# 5️⃣ 번
- name: Publish queenit-app-ui & queenit-web-ui packages
run: npm run publish:libraries
env:
NODE_AUTH_TOKEN: ${{ secrets.GH_TOKEN }}
YAML
복사
•
이로써, 항상 아이콘이 추가될 때마다, 두 패키지가 동시에 같은 버전으로 배포될 수 있습니다.
syncVersion.ts 코드가 궁금하다면? ![](data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==)
•
1.
extractImageAssets
Figma 파일 내에서 추출 대상이 되는 아이콘은 Figma Instance라고 위에서 언급했었습니다. Figma Instance만을 식별하는 과정을 위 함수가 담당합니다.
extractImageAssets 함수 일부 구경하기
2.
saveImageAssetFiles
saveImageAssetFiles 은 extractImageAssets 함수의 호출 결과로 추출된 아이콘 정보를 기반으로 그것을 실제 png, svg 파일로 저장하여 queenit-ui의 bin 폴더에 저장해둡니다.
saveImageAssetFiles 실행 후 png, svg 폴더로 저장되는 이미지 파일들
saveImageAssetFiles 함수 구경하기
•
{/* ... 코드 생략 ... */}
export const exportImageAssets = async () => {
// make src directory
for (const dir of [
appSrcDir,
webSrcDir,
webPngSrcDir,
webSvgSrcDir
]) {
await ensureDir(dir)
}
// make index.ts & index.d.ts files
for (const dir of [appSrcDir, webPngSrcDir, webSvgSrcDir]) {
fs.writeFileSync(join(dir, 'index.ts'), '', 'utf-8')
fs.writeFileSync(join(dir, 'index.d.ts'), '', 'utf-8')
}
fs.appendFileSync(join(webSvgSrcDir, 'index.d.ts'), 'import * as React from \'react\'\n\n', 'utf-8')
Object.values(imageAssets)
.forEach(({ name }) => {
appendImageAssetToApp(name, appSrcDir)
appendImageAssetToWeb(name)
})
}
TypeScript
복사
exportImageAssets 함수를 보면, bin에서 모든 이미지를 순회하면서 packages 내부의 app, web 폴더에 각각 올바른 형태로 이미지를 export하는 코드를 적어줍니다.
appendImageAssetToApp, appendImageAssetToWeb 함수가 각각의 패키지에 맞는 형태로 png, svg 파일을 append해주는 역할을 담당합니다.
프로젝트에서 어떤 형식의 이미지 파일을 어떤 형태로 import하여 사용하는지에 따라 export 코드는 적절히 customize하면 됩니다.
packages/app 에서 이미지 export 방식
packages/web 에서 이미지 export 방식
•
bundler로는 rollup.js이라는 라이브러리를 활용하였습니다. 가장 간단한 번들러 라이브러리를 활용하고 싶었고 png와 svg 이미지를 적절히 번들링하는데 활용할 수 있는 플러그인들을 이미 많이 존재하여서 선택하였습니다.
여기서도 export되어야하는 형식이 다른 만큼 app, web인지에 따라 rollup 설정이 달라집니다.
packages/app 의 rollup.config.js
packages/web 의 rollup.config.js
•
이렇게
번을 실행하여 나온 번들 결과물을 Github package로 배포하는 명령어입니다. 저희는 패키지 두 개 (queenit-app-ui , queenit-web-ui )가 배포되는 것이죠.
배포가 성공하면 슬랙 알림으로 새로운 라이브러리 버전이 배포됐음을 노티하고, 개발자는 프로젝트에서 새로운 라이브러리를 설치하여 바로 추가/수정된 이미지 애셋을 사용할 수 있게 됩니다.
디자인 팀에서 혹시나 중복된 이름을 가진 이미지 애셋을 등록하였다거나, 잘못된 형태로 이미지를 등록하였을 경우, 배포 실패 알림이 가기 때문에,
대규모 마이그레이션 작업
이렇게 완성된 queenit-ui 로, 자동화 시스템의 구축은 끝이 났습니다. 하지만 가장 크고 고통스러운 숙제가 남아있었죠. 바로 지금 사용 중인 이미지 애셋들을 라이브러리에서 꺼내서 사용하도록 전체 교체하는 대규모 마이그레이션 작업이었습니다.
Design 챕터에서는 기존에 사용하던 이미지 애셋들을 모두 정리하여서 export 용 Figma 파일을 새로 만드는 작업이 필요했고, 그 작업이 완료되면 Frontend 챕터에서는 이미지들이 담긴 라이브러리로부터 이미지들을 import하여 사용하도록 전면 교체해야했습니다.
디자인 챕터에서 정리해주신 이미지 애셋 export 용 Figma 파일
프로젝트 내 이미지들을 마이그레이션 하는 작업은 점진적으로 진행하였습니다. 우선 아이콘 개수가 상대적으로 적은 모바일 웹에서 우선적으로 적용하고 문제가 없는 것을 확인한 후, 앱에도 적용하였습니다. 또, 이미지 애셋을 전면 교체 하는 것을 라포랩스의 전수 QA 기간에 맞춰서 작업 하여, 겸사겸사 QA팀에서 앱과 모바일 웹의 전반의 기능들에 대한 QA가 이루어질 때, 이미지 교체로 인한 문제가 없는지 확인될 수 있게 하였습니다.
195개 파일을 건드려서 전면 교체한 모바일 웹의 이미지 애셋들
Design 챕터와 Frontend 챕터에서 힘을 합쳐 원활한 마이그레이션 작업이 이루어졌고, 큰 문제 없이 교체가 완료되었습니다. 이제부터 모든 이미지 애셋은 queenit-ui 를 통해 제공되게 되었고, 글을 쓰고 있는 현시점에 프로세스가 드디어 자리를 잡게 되었습니다.
마치며..
queenit-ui 작업으로 이제 디자이너는 개발자와 직접 소통하지 않고도 이미지 업데이트 사항에 대한 PR을 올려서 알릴 수 있게 되었고, 개발자는 PR이 올라왔다는 알림을 받으면 새로운 버전의 라이브러리를 설치하여서 바로 새로운 이미지를 사용할 수 있게 되었습니다.
이전에 직접 Figma에서 어떤 이미지 애셋을 추가해야할지 찾아보고 또 찾기 어려울 때에는 문의드려야하는 번거로운 프로세스가 많이 사라지게 되었습니다. 그리고 이전에 있었던 같은 이미지 애셋이 서로 다른 이름으로 프로젝트 내에서 관리 되는 문제들이나 서로 다른 이미지들이 같은 이름으로 Figma에서 정의되던 동명이인 문제들도 라이브러리의 컴파일 시점에서 오류를 잡아낼 수 있으니 원천봉쇄할 수 있게 되었습니다.
그래서 이제는 디자이너와 개발자가 소통할 때 같은 이름으로 이미지를 부르고, 찾을 수 있게 되어서 커뮤니케이션 비용이 줄었고, 이미지 전체 교체 작업도 라이브러리 업데이트만 하면 되니 정말 쉬워졌죠.
queenit-ui 자동화로 관리하게 된 퀸잇 색상 팔레트
이미지 작업을 하면서 겸사겸사 퀸잇 프로젝트에서 사용하고 있는 색상 팔레트도 queenit-ui 내부로 옮기는 작업을 하였는데요, 이미지 애셋과 마찬가지로 Figma에 정의된 색상들을 불러오고 이를 export하는 방식으로 색상 팔레트 또한 라이브러리에서 바로 가져다 쓸 수 있도록 만들었습니다.
Figma가 Single source of truth가 되어 프로젝트에서 사용하는 이미지와 컬러를 관리할 수 있게 되었지만, 여전히 queenit-ui는 갈 길이 많이 남았습니다. 저희 디자인 시스템에 정의된 다양한 공통 컴포넌트들 (Typography, Button, Input 등) 도 점점 queenit-ui로 자동화되어서 프로젝트에서 쓸 수 있게 하는 것이 최종적인 목표입니다.
queenit-ui 자동화 코드 작업을 하고 디자인 팀과 논의하며 프로세스를 만들어가는 과정 전반을 경험할 수 있어서 정말 뜻 깊었습니다. 이렇게 재밌고, 도전적인 문제들을 함께 해결하실 분들은 라포랩스에 합류해주세요!