Vite + Electron + React 환경에서 svgr 사용하기

Vite + Electron + React 환경에서 svgr 사용하기

electron-vite

Vite를 한 번 쓴 뒤로는 Webpack으로 돌아가지 못하는 몸이 되었다. 압도적인 빌드 및 HMR 속도를 한 번 겪어보니 도저히 돌아갈 엄두가 나지 않는다.

이번에 진행하고 있는 프로젝트에서 처음에는 닷넷/WPF로 작성하려다가 이것 저것 조건을 따져보니 일렉트론을 쓰는 게 낫다 판단되어 일렉트론으로 전환하였고, 기본 일렉트론 가이드대로 따라보니 웹팩의 느려터진 빌드 속도가 짜증나서 electron-vite를 사용하게 되었다.

SVG Component

이번 프로젝트에는 마치 포토샵마냥 도구 툴바를 구현해야 하는 부분이 있다. 대부분은 heroicons이나 @mui/icons-material로 해결이 되었지만 안 되는 부분 역시 있었기에 이러한 부분은 직접 제작한 SVG나 무료 라이센스의 SVG를 받아서 쓰려 했다.

문제는, SVG 컴포넌트를 사용하려 하니 자꾸 에러가 났다는 것이다.

vite-plugin-svgr

SVG 컴포넌트를 사용하기 위해 vite-plugin-svgr을 패키지에 추가했다. 설정하라는 대로 env.d.ts도 수정하고, electron.vite.config.ts도 수정했지만 정상적으로 작동하지 않았다.

SyntaxError: The requested module '/[CENSORED]/move-arrows.svg?t=1699422381493&import' does not provide an export named 'ReactComponent' (at [CENSORED].tsx?t=1699422908031:26:10)

import문은 다음과 같다.

import { ReactComponent as MoveArrows } from "@assets/move-arrows.svg";

문제 파악 및 해결

일단, 문제는 오래된 글이었다. 말 그대로 너무 오래된 글이라 이전 버전의 라이브러리 또는 vite에 대한 내용이 적혀있던 것 같다. 어떤 글인지 정확히 특정해 밝히진 않겠지만, 내가 본 세 개의 국내 블로그 글들은 모두 위처럼 import문을 작성하라고 알리고 있었다.

그러나, 그게 아니었다. **공식 문서**에 따르면 컴포넌트를 쓰려면 단순히 ?react 쿼리를 import 할 svg 대상 끝에 추가하라 한다.

import MoveArrows from "@assets/move-arrows.svg?react";

(또한 default를 import하기 때문에 중괄호로 묶지 말아야 한다.)

위처럼 작성하니 아무 문제 없이 정상적으로 import됨을 확인할 수 있었다.

electron-vite 환경에서 vite-plugin-svgr 사용법 요약

  1. 일단 vite-plugin-svgr을 설치한다. 내 경우 pnpm을 사용했다.
pnpm i -D vite-plugin-svgr
  1. renderer/src/env.d.ts에 다음 줄을 추가한다.
/// <reference types="vite-plugin-svgr/client" />
  1. (옵션) 원하는 경로에 원하는_이름.d.ts 파일을 만들고 이를 tsconfig.web.json의 includes에 추가한다.
    옵션인 이유는 모든 블로그 글에서 이를 진행해야 타입스크립트에서 정상적으로 사용할 수 있다 하였으나, 테스트 결과 없어도 잘 작동했다.
    d.ts 파일의 내용은 다음과 같다.
declare module "*.svg" {  
  import React = require("react");  
  export const ReactComponent: React.FC<React.SVGProps<SVGSVGElement>>;  
  const src: string;  
  export default src;  
}
  1. electron.vite.config.ts에서 rendererpuginssvgr()을 추가한다.
// ...
import svgr from "vite-plugin-svgr";
// ...
export default defineConfig({
    main: {
        plugins: [externalizeDepsPlugin(), svgr()],
    },
    preload: {
        plugins: [externalizeDepsPlugin(), svgr()],
    },
    renderer: {
        /* ... */
        plugins: [react(), svgr()],
    },
});
  1. (사용) 원하는 svg 파일을 임포트하되, 컴포넌트로 사용하려면 끝에 ?react 쿼리를 붙여준다.
// 올바른 컴포넌트 임포트
import MySvgNameBlahBlah from "@assets/icons/cursor.svg?react";

// 올바르지 않은 컴포넌트 임포트
import ThisIsPathImport from "@assets/icons/cursor.svg";
import { ReactComponent as MySvgNameBlahBlah2 } from "@assets/icons/cursor.svg";

댓글

  1. Your post was a joy to read. Thank you for sharing your wisdom!

    답글삭제
    답글
    1. I'm glad to hear you enjoyed reading it. I hope the information was helpful.

      삭제

댓글 쓰기

이 블로그의 인기 게시물

C# 남아도는 메모리에도 불구하고 OutOfMemoryException이 발생한다면?

USB를 뒤는 괜찮은데 앞에 꽂으면 인식이 힘들다?

MySQL 데이터 타입과 Java 데이터 타입 비교/매칭