모노레포에서 SVGR 기반 UI 아이콘 시스템과 공통 컴포넌트 구축하기

kiwon kim·2025년 7월 20일
0

Frontend

목록 보기
29/30
post-thumbnail

1. 폴더 구조 설계

travel-planning-app/
  apps/
    web/
      src/
        pages/
          Home.tsx
      package.json
    admin/
      ...
  packages/
    ui/
      src/
        icons/           # SVG 원본 파일 (공통)
        icons-generated/ # generate:icons로 생성된 React 컴포넌트 (공통)
        button.tsx
        card.tsx
        index.ts         # 모든 컴포넌트와 아이콘 export
      package.json
  pnpm-workspace.yaml
  ...
  • 공통 아이콘packages/ui/src/icons/에 SVG로 관리
  • icons-generated/에 SVGR로 변환된 React 컴포넌트가 생성됨
  • index.ts에서 모든 아이콘과 UI 컴포넌트를 export

2. SVGR 및 generate:icons 스크립트 설정

2-1. SVGR 설치

packages/ui에서 SVGR을 설치합니다.

cd packages/ui
pnpm add -D @svgr/cli

2-2. generate:icons 스크립트 추가

packages/ui/package.json

{
  "scripts": {
    "generate:icons": "svgr --typescript --icon --out-dir src/icons-generated src/icons"
  }
}

3. SVG 아이콘 파일 추가

packages/ui/src/icons/Search.svg

<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
  stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">
  <circle cx="11" cy="11" r="8"/>
  <line x1="21" y1="21" x2="16.65" y2="16.65"/>
</svg>

packages/ui/src/icons/User.svg

<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
  stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">
  <circle cx="12" cy="7" r="4"/>
  <path d="M5.5 21a10 10 0 0 1 13 0"/>
</svg>

4. 아이콘 컴포넌트 생성

터미널에서 아래 명령어 실행

pnpm run generate:icons

결과:
packages/ui/src/icons-generated/Search.tsx, User.tsx 등 생성


5. 아이콘 export 설정

packages/ui/src/index.ts

// UI 컴포넌트 export
export * from "./button";
export * from "./card";

// 아이콘 export
export { default as SearchIcon } from "./icons-generated/Search";
export { default as UserIcon } from "./icons-generated/User";
// ...추가 아이콘도 동일하게 export

아이콘이 많다면 아래처럼 자동화도 가능합니다:

// packages/ui/src/icons-generated/index.ts
export { default as SearchIcon } from "./Search";
export { default as UserIcon } from "./User";
// ...자동 생성 스크립트로 관리 가능

그리고 index.ts에서

export * from "./icons-generated";

6. 앱에서 사용 예시

apps/web/src/pages/Home.tsx

import React from "react";
import { Button, Card, SearchIcon, UserIcon } from "@myorg/ui";

const Home: React.FC = () => (
  <Card>
    <Button leftIcon={<SearchIcon width={16} height={16} />}>
      검색
    </Button>
    <UserIcon width={24} height={24} color="#666" />
  </Card>
);

export default Home;

7. 타입스크립트 설정

packages/ui/tsconfig.json

{
  "compilerOptions": {
    "declaration": true,
    "declarationDir": "dist",
    "outDir": "dist",
    "esModuleInterop": true,
    "jsx": "react-jsx",
    "module": "ESNext",
    "moduleResolution": "Node",
    "target": "ESNext",
    "strict": true,
    "skipLibCheck": true
  },
  "include": ["src"]
}

앱의 tsconfig.json에서
@myorg/ui가 node_modules 또는 패키지 경로에서 resolve되도록 설정


8. 빌드 및 자동화 팁

  • prebuild에 generate:icons 추가
    packages/ui/package.json에 아래처럼 추가하면, 빌드 전에 항상 최신 아이콘 컴포넌트가 생성됩니다.
{
  "scripts": {
    "prebuild": "pnpm run generate:icons",
    "build": "tsc"
  }
}
  • 앱에서는 별도 generate:icons 필요 없음
    아이콘은 오직 @myorg/ui에서만 관리/생성

9. 장점

  • 아이콘/컴포넌트 모두 @myorg/ui에서 import
    → 앱 코드가 일관되고, 유지보수/확장성 뛰어남
  • 타입 안전
    → SVGR의 --typescript 옵션으로 타입 안전한 컴포넌트 생성
  • 공통 UI와 유연한 조합
    → 공통 UI 컴포넌트와 아이콘을 자유롭게 조합
  • 확장성
    → 새로운 아이콘 추가 시, generate:icons 후 export만 하면 모든 앱에서 즉시 사용 가능
profile
FOR_THE_BEST_DEVELOPER

0개의 댓글