← 글 목록

notes

SVGR

SVGR로 SVG를 React 컴포넌트로 변환·사용하는 설정과 주의점 메모.

  • SVG 를 손으로 JSX 로 옮기지 않아도 SVGR 이 <svg> 컴포넌트로 바꿔 준다.
  • fill="currentColor" 로 바꾸면 글자색을 따라가서 테마 연동과 props 제어가 쉽다.
  • 아이콘은 SVGR, 사진과 큰 일러스트는 img 나 Next Image 로 나눈다.

SVGR 이 뭔가

logo.svg 를 손으로 JSX 로 옮기지 않아도, 기계가 <svg>...</svg> 를 돌려주는 컴포넌트로 바꿔 준다.

비유하면 이렇다.


왜 쓰나

SVG 를 <img> 로 쓰면 색을 바꾸기 어렵다. fill 을 CSS 로 못 건드리고, currentColor 로 테마를 따라가게 할 수도 없고, 크기나 className 을 props 로 넘기기도 불편하다.

<img src="/icons/search.svg" />

SVGR 로 컴포넌트로 만들면 이렇게 쓴다.

<CommonSearch className="text-semantic-primary" width={20} />
  • fill="currentColor" 이면 글자색을 따라간다.
  • width, height, className 을 props 로 조절한다.
  • TypeScript 자동완성이 된다.

동작 방식 두 가지

문서에 나오는 방식과 회사 모노레포에서 쓰는 방식이 다르다.

① 빌드할 때 변환 (번들러 플러그인)

import 하는 순간 번들러가 SVG 를 컴포넌트로 바꾼다. 문서의 ReactComponent as Logo 는 CRA 와 webpack(@svgr/webpack) 시절 문법이다.

// webpack + @svgr/webpack (예전 CRA 방식)
import { ReactComponent as Logo } from './logo.svg';

// Vite + vite-plugin-svgr 4.x 이상
import Logo from './logo.svg?react';

Vite 는 vite-plugin-svgr 를 쓰는데, 4.x 부터 ?react 를 붙여야 컴포넌트로 가져온다. Next.js 는 webpack 이면 @svgr/webpack 로더를, Turbopack 이면 turbopack.rules 에 같은 로더를 등록한다.

② 미리 변환해 두기 (CLI)

회사 모노레포는 이 방식이다. SVG 를 넣고, 스크립트를 돌리고, 만들어진 TSX 를 커밋한다.

pnpm run svgr:icons
svg/Name=search.svg
    ↓  SVGR CLI
common/CommonSearch.tsx
    ↓  import
import { CommonSearch } from '@monorepo/ui/icons/common'
실제 생성 결과
import * as React from "react";
import type { SVGProps } from "react";
const CommonSearch = (props: SVGProps<SVGSVGElement>) => (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    width={24}
    height={24}
    fill="currentColor"
    viewBox="0 0 24 24"
    {...props}
  >
    <path d="M16.375 10.125a6.25 6.25 0 1 0-12.5 0 ..." />
  </svg>
);
export default CommonSearch;

{...props} 덕분에 나머지 props 는 그대로 <svg> 에 넘어간다.


모노레포 워크플로

아이콘 카테고리는 common, color, navigation, detail 네 개다. 설정은 .svgrrc.js 와 scripts/svgr-icons.js 가 맡는다. @monorepo/ui/icons 는 경로 별칭(alias)이다.


문서의 장점을 쉬운 말로

동적 import 예시는 문서에 ReactComponent 와 img src 가 섞여 있어서 헷갈린다. 실무에서는 아이콘 이름이 정해져 있으면 정적 import, 런타임에 바꿔야 하면 아이콘 맵 객체(export:icon-map 스크립트)를 쓴다.


SVGR vs img, Next Image

아이콘은 SVGR 로, 사진은 OptimizedImage 나 Next Image 로 간다.


주의할 것

  • SVG 가 너무 복잡하면 TSX 도 커진다. Figma 에서 내보내기 전에 단순화한다.
  • CLI 방식은 런타임 변환이 아니다. SVG 를 추가하거나 바꾸면 pnpm run svgr:icons 로 다시 만들고 커밋해야 한다.
  • fill 이 하드코딩된 SVG 는 색이 안 바뀐다. .svgrrc.js 에서 currentColor 로 치환하게 해 두었다.
  • 새 아이콘은 svg/ 폴더에 넣고 스크립트를 돌리는 게 전부다.

한 줄 요약

SVGR 은 SVG 를 손으로 JSX 로 안 짜도 되게 해 주는 변환기다. 회사 모노레포는 빌드마다 변환하는 대신 svgr:icons 로 .tsx 를 미리 만들어 두고, 앱은 @monorepo/ui/icons 만 import 한다. 문서의 webpack 예시는 설치 방식이 다를 뿐, SVG 를 React 컴포넌트로 바꾼다는 개념은 같다.