[React] Vite 프로젝트에서 SVG를 React 컴포넌트로 자동 변환
이 블로그 포스팅을 참고하였으나, 버전이 올라감에 따라 설정이 충돌되는 부분이 생겨 업데이트 버전을 직접 작성한다.
1. SVG를 React에서 다루는 두 가지 방식
SVG 파일을 React에서 사용하는 방법은 크게 두 갈래로 나뉜다. 하나는 빌드 시점에 번들러가 SVG를 React 컴포넌트로 변환하도록 맡기는 방식이다. vite-plugin-svgr이 여기에 해당한다. import Icon from "./icon.svg?react"처럼 쿼리 문자열 한 줄로 컴포넌트를 얻을 수 있다.
다른 하나는 @svgr/cli를 사용해 SVG를 .tsx 파일로 미리 변환해 두는 방식이다. 컴파일 대상이 되는 실제 소스 파일로 존재하므로, 에디터에서 컴포넌트 이름으로 바로 이동하거나 참조를 추적하는 데 유리하다.
두 방식은 배타적이지 않다. 이 프로젝트에서는 @svgr/cli로 사전 생성하는 경로를 기본으로 두고, vite-plugin-svgr은 런타임 import가 필요한 경우에 대비해 병행 등록해 둔다.
2. 디렉터리 구조
public/svg에 원본 SVG를 넣고, pnpm svgr 명령으로 src/assets/svg 아래에 .tsx 컴포넌트를 생성한다. 이후 컴포넌트 import는 @/assets/svg/<Name> 경로로 이루어진다.
3. 수정한 파일
package.json
SVG 일괄 변환 스크립트를 추가한다.
각 플래그의 역할은 다음과 같다.
-d src/assets/svg: 변환 결과물을 저장할 디렉터리--ignore-existing: 이미 존재하는 파일은 덮어쓰지 않음--typescript:.tsx확장자와 타입 시그니처로 출력--no-dimensions: 원본 SVG의width,height속성을 제거. 컴포넌트 사용 시점에 크기를 props로 자유롭게 지정할 수 있다.- 마지막 인자
public/svg: 변환할 원본 SVG가 위치한 디렉터리
vite.config.ts
vite-plugin-svgr을 플러그인으로 등록한다. 런타임에서 import Icon from "./icon.svg?react" 형태의 import가 필요한 경우에 대비한 설정이다.
.svgrrc.json (신규 생성)
svgr CLI의 변환 동작을 제어하는 설정 파일이다. 프로젝트 루트에 생성한다.
prettier: false: svgr 내부 prettier 포맷 단계를 비활성화한다. 프로젝트에 이미husky+lint-staged가 구성되어 있으므로 커밋 시점에 일괄 포맷된다.jsxRuntime: "automatic": React 17+의 automatic JSX 런타임에 맞게 생성물을 출력한다. 이 옵션이 없으면 불필요한import * as React from "react"구문이 생성되어noUnusedLocals규칙에 걸린다.
4. 변환 과정
pnpm svgr 명령을 실행하기 전, src/assets/svg 디렉터리가 비어 있는 상태다.

터미널에서 pnpm svgr을 실행한다.

public/svg 아래의 SVG 파일 3개가 src/assets/svg에 .tsx 컴포넌트로 생성된다.

생성된 컴포넌트는 일반 React 컴포넌트처럼 import해서 사용한다.
이 프로젝트는 TanStack Router의 파일 기반 라우팅을 사용한다. TanStackRouterVite 플러그인이 src/routes 디렉터리를 감시하다가, 파일을 추가하면 해당 파일명에 대응하는 경로를 자동으로 라우트 트리에 등록한다. src/routes/index.tsx를 만들면 / 경로가 자동으로 생성되는 방식이다. 개발자가 직접 라우트를 선언할 필요 없이 파일을 올바른 위치에 두는 것만으로 경로가 완성된다.
단, SVG 자동 변환 설정 자체는 TanStack Router와 무관하다. CRA나 React Router를 사용하는 프로젝트에서도 package.json 스크립트와 .svgrrc.json만 동일하게 추가하면 같은 방식으로 동작한다.
아래는 src/routes/index.tsx의 실제 코드다.
각 아이콘 컴포넌트에 className="h-20 w-20"을 전달하고 있다. Tailwind CSS에서 h-20, w-20은 각각 height: 5rem, width: 5rem으로, 기본 폰트 크기(16px) 기준 80px에 해당한다. @svgr/cli로 생성된 컴포넌트는 SVGProps<SVGSVGElement>를 props로 받으므로, 이처럼 className을 그대로 넘겨 스타일링할 수 있다.

결론
이렇게 설정하면 Figma에서 다운받은 SVG 파일을 매번 컴포넌트 파일로 직접 생성해야 하는 반복 작업을 자동화할 수 있다. public/svg에 파일을 넣고 pnpm svgr을 실행하는 것만으로 끝난다.