[Front-end] 개발자 공부

아이콘 효율적으로 관리하기

MOLLY_ 2025. 1. 1. 07:00
728x90

< 목차 >

1. 폴더 구조

2. Icon.tsx 컴포넌트

3. iconSizes.ts: Icon 크기 관리

4. tailwind.config.ts 에 제공되지 않는 크기(30px) 추가

5. globals.css에서 SVG에 적용할 기본 스타일 설정

6. 아이콘 컴포넌트 생성

7. 아이콘 사용

8. [참고] SVG 최적화 방법 2가지

 

 

이번 프로젝트에서는 사용하는 아이콘이 많으므로, 아이콘을 개별적으로 import해서 사용하는 방식이 아닌 Icon.tsx 을 만들어 중앙 관리 컴포넌트를 사용하는 방식으로 관리할 것이다.

 

직전 프로젝트에서 아이콘의 SVG 코드가 반복되고, 관리가 불편했어서 이번 프로젝트에선 그 부분을 해결하고자 한다.

 

Icon.tsx와 같은 아이콘 컴포넌트를 만드는 이유는 아이콘 관리 및 사용의 일관성편의성을 높이기 위함이다.

 

 

1. 폴더 구조

src/
├── components/
│   ├── Icon/
│   │   ├── Icon.tsx                # 첫 글자 대문자 (컴포넌트 폴더/일반 폴더 구분)
│   │   ├── iconSizes.ts            # 아이콘 크기 설정
│   │   └── icons/                  # 아이콘 파일 폴더
│   │       └── ChevronLeft.tsx     # 개별 아이콘 파일

 

아이콘은 크기별 또는 카테고리별로 관리하여 재사용성을 높이고, 필요한 크기별로 쉽게 접근할 수 있도록 할 것이다. 이로 인해 ‘아이콘의 일관된 사용, 중앙 집중식 관리, 확장성’이라는 장점을 얻을 수 있다.

 

- Icon.tsx: 재사용 가능한 Icon 컴포넌트 정의 (모든 SVG를 동적으로 로드하여 코드 중복 제거)

- iconSizes.ts: 아이콘 크기를 정의하여 크기 변경을 중앙에서 관리

- icons/: 아이콘 파일들 저장

- Tailwind 통합: 색상, 크기, 스타일을 Tailwind 클래스와 쉽게 결합 가능

 

 

2. Icon.tsx 컴포넌트

: Icon.tsx에서 SVG 아이콘을 동적으로 로드하고, 크기와 스타일 관리

Icon.tsx는 아이콘 이름을 기반으로 아이콘을 렌더링한다. 이 파일에서 모든 아이콘을 중앙에서 관리한다.

 

// Icon.tsx

import React from 'react';

import iconSizes, { IconSize } from './iconSizes';
import ChevronLeft from './icons/ChevronLeft';

// TODO: 아이콘 이름 따로 관리
const iconsName: Record<string, React.FC<{ className?: string }>> = {
  ChevronLeft,
};

// TODO: 아이콘 타입 따로 관리
interface IconProps {
  name: keyof typeof iconsName;
  size?: IconSize;
  className?: string;
}

const Icon: React.FC<IconProps> = ({
  name,
  size = 'm',
  className = '',
}: IconProps) => {
  const Component = iconsName[name];
  const iconSize = iconSizes[size];

  if (!Component) {
    return null;
  }

  return <Component className={`${iconSize} ${className}`} />;
};

export default Icon;

 

아이콘 사이즈 뿐만 아니라 아이콘 이름도 따로 관리한다.

위 코드는 한눈에 알아보기 쉽게 하나에 다 담았다. 파일을 분리하면 다음과 같다.

 

iconsNames.ts

 

@/types/IconProps.ts

 

Icon.tsx

 

const icons: Record<string, React.FC<{ className?: string }>> = {
  ChevronLeft,
};

 

Webpack을 사용할 경우, 다르게 처리해 줄 수 있지만 이번엔 수동으로 처리해도 문제가 되지 않을 것 같아서 그렇게 구현했다.

 

- 장점: 추가적인 빌드 설정 없이 간단하게 사용 가능

- 단점: 아이콘이 많아질수록 코드가 길어지고 관리가 어려워질 수 있음

 

위처럼 장단점이 아주 뚜렷하다.

그래도 import가 늘어나는 것보단 이렇게 아이콘 이름을 따로 관리하는 편이 낫다고 판단했다.

 

새로운 아이콘이 추가될 떄마다 아이콘 이름을 최초에 1번만 작성해주면 name 프로퍼티를 통해 바로 적용이 가능하기 때문이다.

 

 

3. iconSizes.ts: Icon 크기 관리

아이콘 크기별 설정을 iconSizes.ts에 작성하여 필요할 때 중앙에서 수정 가능하게 하자.

 

export type IconSize = 'xl' | 'l' | 'm' | 's';

const iconSizes: Record<IconSize, string> = {
  xl: 'w-15 h-15', // 60px
  l: 'w-7.5 h-7.5', // 30px
  m: 'w-6 h-6', // 24px
  s: 'w-4.5 h-4.5', // 18px
};

export default iconSizes;

 

 

4. tailwind.config.ts 에 제공되지 않는 크기(30px) 추가

[출처] Tailwind CSS 공식 문서 (https://tailwindcss.com/docs/width)

 

Tailwind CSS에 없는 크기로 지정하려면, 기본적으로 제공되지 않는 크기(e.g. 30px)를 Tailwind의 확장 기능으로 커스터마이징하면 된다.

 

Tailwind의 theme.extend를 사용하여 새로운 크기를 추가하면, 클래스 이름으로 쉽게 사용할 수 있다.

 

// tailwind.config.ts

import type { Config } from 'tailwindcss';

export default {
  theme: {
    extend: {
      spacing: {
        '4.5': '18px', // 이렇게 px 추가
        '7.5': '30px',
        '15': '60px',
      },
    },
  },
} satisfies Config;

 

iconSizes 를 수정하여 xl 사이즈를 30px 로 매핑하면 된다.

 

 

5. globals.css에서 SVG에 적용할 기본 스타일 설정

/* globals.css */

@layer base {
	svg {
	  display: inline-block;
	  vertical-align: middle;
	  fill: currentColor; /* 텍스트 색상과 동일하게 적용 */
	}
}

 

 

6. 아이콘 컴포넌트 생성

이제 components/Icon/icons 폴더에 아이콘을 싹 다 때려넣으면 된다!

 

인자엔 className을 넣고, return에 SVG 코드를 넣자.

 

const ChevronLeft = ({ className }: { className?: string }) => {
  return (
    
      
    
  );
};

export default ChevronLeft;

 

fill="currentColor 를 통해 텍스트 색상(text-{color})에 따라 색상을 동적으로 변경한다. 아까 globals.css에서 설정을 해줬기 때문에 가능하다.

 

 

7. 아이콘 사용

'use client';

import Icon from '@/components/Icon/Icon';

export default function Test() {
  return <Icon name="ChevronLeft" size="xl" className="text-main" />;
}

 

이제 아이콘 컴포넌트명을 하나하나 import 하지 않고, Icon 하나만 import 해도 되게 되었다.

SVG를 동적으로 로드하여 코드 중복을 없애고, 프로퍼티로 넘김으로써 반복되는 많은 코드를 줄였다.

 

iconSizes.ts에서 크기 조정, globals.css에서 스타일 관리를 하기 때문에 유지보수도 쉬워졌다.

 

<Icon>의 name 프로퍼티를 상수화해도 좋을 것 같다.

자동완성이 안 돼서 오타가 있을 경우, 아이콘이 안 보일 수 있기 때문이다.

 

 

8. [참고] SVG 최적화 방법 2가지

1. SVG 최적화: 프로젝트에 SVG를 추가하기 전에 SVGO 같은 도구로 최적화 (파일 크기를 줄이고 성능 개선)

2. 동적 로드 지원: 아이콘이 많아질 경우 React.lazy와 Suspense를 사용해 필요할 때 로드, 번들 크기와 초기 로드 시간 최적화

   - [코드 스플리팅] 아이콘을 동적으로 로드하여 초기 번들 크기를 줄일 수 있음

 

SVG 최적화와 동적 로드 최적화는 아이콘 관리가 간결해지고, 성능 최적화 및 효율성이 극대화된다.

 

나는 .svg로 끝나는 파일로 SVG를 관리하지 않아서 이 2가지 최적화 방법을 사용하지 않았다.

 

아이콘을 효율적으로 사용하기 위해 도입한 방법 때문에 적용이 어렵다.

Icon.tsx를 통해 파라미터를 받아서 실제 SVG가 있는 컴포넌트에서 파라미터를 처리해줘야 하기 때문이다. 파라미터를 받으려면 .tsx(컴포넌트)로 작성할 수밖에 없기 때문에 적용되지 않는다.

 

 

728x90