[Mere] @svgr/webpack 충돌 해결하기

BangDori·2023년 12월 27일
0

Mere

목록 보기
5/5

오늘은 typescript + react + webpack을 활용하고 있는 저희 팀에서 SVG를 컴포넌트로 어떻게 분리하였는지와 컴포넌트화를 진행하는 과정에서 발생한 트러블 슈팅을 공유하려고 합니다.

📕 목차

  1. SVG를 컴포넌트화 시키게 된 이유
  2. SVG 컴포넌트 분리 및 적용
  3. webpack 충돌 해결하기

SVG를 컴포넌트화 시키게 된 이유

기존에 로그인뿐만 아니라 많은 컴포넌트에서 SVG를 활용하고 있었습니다. 그런데 로그인 컴포넌트를 타입스크립트로 마이그레이션을 진행하는 도중 SVG가 컴포넌트의 가독성을 저하시키고 있다는 생각이 들었습니다.

<form className='login-form' method='post' onSubmit={onLogin}>
  // ...
  <div className='id-save-container'>
    <button
      type='button'
      className={`id-save-btn ${isSave && 'id-save-btn__active'}`}
      onClick={isSaveToggle}
    >
      {isSave && (
        <svg
          width='10'
          height='10'
          viewBox='0 0 13 13'
          fill='none'
          xmlns='http://www.w3.org/2000/svg'
        >
          <path
            d='M0.773438 5.52287L5.00052 11.2129L12.154 1.13281'
            stroke='white'
            stroke-width='1.5'
          />
        </svg>
      )}
    </button>
    <p className='id-save-message'>{FORM_PLACEHOLDERS[userType].save}</p>
  </div>
  <p className='login-error-message'>{errors?.errorMessage}</p>
  <button
    type='submit'
    className='login-submit-btn'
    disabled={isSubmitting}
  >
    {isSubmitting ? <LoadingSpinner /> : '로그인'}
  </button>
</form>

이런 svg 코드가 한 컴포넌트 내부에 1개만 들었갔음에도 이렇게 JSX 코드가 지저분해지는데, 2개 혹은 그 이상이 들어가게 된다면 추후 유지 보수 단계에서 컴포넌트 관리가 정말 어려워질 것이라고 예상을 해 이를 컴포넌트화시켜 분리하는 방법에 대해 고려하게 되었습니다.

SVG 컴포넌트 분리 및 적용

SVG를 컴포넌트로 분리하는 과정은 어렵지 않았습니다. 우선 SVG를 assets에 따로 분리하였습니다.

<svg
  width='10'
  height='10'
  viewBox='0 0 13 13'
  fill='none'
  xmlns='http://www.w3.org/2000/svg'
>
  <path
    d='M0.773438 5.52287L5.00052 11.2129L12.154 1.13281'
    stroke='white'
    stroke-width='1.5'
  />
</svg>

이후 해당 프로젝트에서는 webpack을 이용해 dev Server를 가동시키고 있어 webpack의 module@svgr/webpack 라이브러리를 추가해 주었습니다.

// 로더
module: {
  rules: [
    {
      test: /\.(png|jpe?g|gif|svg)$/i,
      type: 'asset/resource',
    },
    {
      test: /\.svg$/,
      use: ['@svgr/webpack'],
    },
  ],
}

위와 같이 한 후 SVG를 컴포넌트로 불러오니 이전보다 컴포넌트의 가독성이 향상된 것을 볼 수 있었습니다.

<form className='login-form' method='post' onSubmit={onLogin}>
  // ...
  <div className='id-save-container'>
    <button
      type='button'
      className={`id-save-btn ${isSave && 'id-save-btn__active'}`}
      onClick={isSaveToggle}
    >
      {isSave && <SaveCheck />}
    </button>
    <p className='id-save-message'>{FORM_PLACEHOLDERS[userType].save}</p>
  </div>
  <p className='login-error-message'>{errors?.errorMessage}</p>
  <button
    type='submit'
    className='login-submit-btn'
    disabled={isSubmitting}
  >
    {isSubmitting ? <LoadingSpinner /> : '로그인'}
  </button>
</form>

하지만 위와 같이 설정한 후, 프로젝트를 확인해 보니 SVG가 로딩이 되지 않았고 에러가 발생하고 있었습니다.

webpack 충돌 해결하기

에러 문구에서 SVG 컴포넌트가 로딩이 되고 있지 않음을 확인할 수 있었고, ChatGPT를 통해 이를 확인해 본 결과 웹팩 모듈 내부를 확인해보니 SVG에 대한 규칙 충돌이 발생하고 있는 것을 확인할 수 있었습니다.

module: {
  rules: [
    {
      test: /\.(png|jpe?g|gif|svg)$/i,
      type: 'asset/resource',
    },
    {
      test: /\.svg$/,
      use: ['@svgr/webpack'],
    },
    // 기타 규칙들...
  ]
}

규칙 간의 충돌 해결: 두 규칙 중 하나만 .svg 파일에 적용되도록 설정을 조정합니다. 예를 들어, .svg 파일을 리액트 컴포넌트로 사용하려면 asset/resource 규칙에서 .svg 확장자를 제외하고, @svgr/webpack 규칙을 유지합니다.

규칙의 순서 변경: 웹팩은 규칙을 배열의 순서대로 처리합니다. @svgr/webpack 규칙을 asset/resource 규칙보다 먼저 배치하여, .svg 파일이 먼저 @svgr/webpack에 의해 처리되도록 할 수 있습니다.

SVG를 assets/resource 규칙에서 제외하고, svgr/webpack에만 규칙이 적용되도록 수정한 후에 정상적으로 적용이 되는 것을 확인할 수 있었습니다.

참고

profile
Happy Day 😊❣️

0개의 댓글