1. 다양한 상황에서 이미지 불러오는 방법
1. CRA
[public]
이미지 태그가 아닌 곳에서 `backgroundImage`로 불러올 때
<div
className="pt-28 pb-12"
style={{
backgroundImage: `url(${이미지경로변수})`,
backgroundPosition: "center", // 이미지 위치
backgroundSize: "cover", // 이미지 꽉차게
backgroundRepeat: 'no-repeat', // 이미지 반복 지정
width:'250px' // 배경이미지 크기
}}
>
</div>
이미지(img) 태그에서 소스 코드로 불러올 때 cra는 `process.env.PUBLIC_URL`로 public 폴더에 접근할 수 있게 default로 되어 있다.
<img
className='w-[121px] h-[115px] object-cover z-10 border rounded-md'
src={`${process.env.PUBLIC_URL}/images/testImage.jpg`}
alt='photoThumb'
/>
[인터넷 이미지 주소]
const image =
'https://cdn.pixabay.com/photo/2019/07/30/05/53/dog-4372036_1280.jpg';
<img src={`${image}`} alt='photoThumb' />
혹은 그냥
<img src='https://cdn.pixabay.com/photo/2019/07/30/05/53/dog-4372036_1280.jpg' alt='photoThumb' />
[src 폴더의 이미지 불러오기]
1. svg, 이미지 파일 다 됨.
import Badge from '../assets/images/Badge1.svg';
<img
className='image'
src={Badge}
alt='no'
/>
2. (svg는 안 되는 듯?)
<img
className='image'
src={require('../assets/images/Badge1.jpg')}
alt='no'
/>
3. ReactComponent로 svg 불러오기
import { ReactComponent as LogoText } from '../../assets/images/Poodaeng.svg';
다음과 같은 문법으로 default export ReactComponent를 as를 통해 별명을 붙여서 컴포넌트 처럼 활용할 수 있다.
<div className='f-fc-ic gap-3 mt-40 w-full'>
<LogoText width='8.75rem' height='4.34625rem' fill='#FFFFFF' />
</div>
2. vite
public폴더에 파일이 있는 경우
(root경로에서 public 폴더 내부의 images 폴더에 파일이 있을 경우)
cra와 마찬가지로 여러 방법이 있다.
public 폴더 내부의 assets들은 root path로 제공되기 때문에 특별한 절대 경로 세팅이 따로 필요없다.
1. 상단에 import 구문을 다음과 같이 절대 경로로 쓴다.
(eslint 세팅 때문에 나는 public 을 빼지는 않았다. 빼도 무방하다. 프로젝트별 컨벤션을 따르자.)
import mysign from '/images/my-sign-2-x.svg';
import mysign from 'public/images/my-sign-2-x.svg';
/* src 폴더 내부에서 쓰인 것이 아니기 때문에 ?url 을 붙여주는 게 좋은 것 같다. */
import mysign from 'public/images/my-sign-2-x.svg?url';
그런 다음 img 태그에서 src에 넣어주면 된다.
<img src={mysign} alt='my-sign' />
2. img 태그에서 바로 불러올 수도 있다.
vite 문서에서는 4번 처럼 하라고 한다.
/* 방법 1 : 절대경로 */
<img src={'images/my-sign-2-x.svg'} alt='my-sign' />
/* 방법 2 : 절대경로 2 -- 이게 왜 됨?❓ */
<img src={'./images/my-sign-2-x.svg'} alt='my-sign' />
/* 방법 3 : 절대경로 3 (추천: 목적이 뚜렷해)*/
<img src={'images/my-sign-2-x.svg?url'} alt='my-sign' />
/* 방법 4 : 절대경로 4 (추천: vite 문서에서 이렇게 하라고 함) */
<img src={'/images/my-sign-2-x.svg'} alt='my-sign' />
/* 방법 5 : 상대경로 */
<img src={'../../public/images/my-sign-2-x.svg'} alt='my-sign' />
3. background-image로 불러오기.
/* 1 */
<div className='h-48 w-48 bg-no-repeat' style={{ backgroundImage: `url(images/my-sign-2-x.svg?url)` }} />
/* 2 */
<div className='h-48 w-48 bg-no-repeat' style={{ backgroundImage: `url(/images/my-sign-2-x.svg?url)` }} />
4. svg 파일 컴포넌트로 불러오기
vite의 경우 CRA처럼 svg 파일을 ReactComponent로 불러와서 사용하려면 약간의 세팅이 필요하다.
public폴더가 아니라 src폴더 내에 svg 파일이 위치해야 한다는 점은 cra와 동일하다.
그렇지 않으면(public 에서 import 하려고 하는 경우) 아래 절차를 따라 갔을 때 다음과 같은 에러를 볼 것이다.

@svgr 이라는 라이브러리를 사용할 것이다.
소개 문구를 보면 이렇게 두 줄 있다.
SVGR is an universal tool to transform SVG into React components.
SVGR takes a raw SVG and transforms it into a ready-to-use React component.
SVG 파일을 리액트 컴포넌트화해서 사용하는 기능을 제공해준다.
npm install --save-dev @svgr/rollup
yarn add --dev @svgr/rollup
pnpm add -D @svgr/rollup


@svgr 전체를 설치하는게 아니라 번들링 툴에 맞게 설치하는 것을 알 수 있다. 우리는 그 중에서 rollup 용을 설치한 것이다. 공식 문서가 따로 있다. 오른쪽 링크를 참고하여 세팅을 해줬다. https://react-svgr.com/docs/rollup/
아래 세팅을 따라와준다.
// vite.config.js
import svgr from '@svgr/rollup';
export default {
// ...
plugins: [..., svgr(), ...], // svgr() 위치 아무데나 상관없다.
};
옵션은 참고로 이 사이트에 들어가면 설정할 수 있는 svgr 옵션들을 알 수 있다.
따로 옵션 설정이 없이 svgr을 호출하기만 해도 default로 설정되어 있는 값들이 있어서 여기까지만 하면 그냥 vite 리액트에서는 다음과 같이 사용이 가능하다.
import { ReactComponent as Logo } from './logo.svg'
React / Typescript 의 경우
React / Typescript의 경우 추가적인 타입 세팅을 해줘야 한다. (깃헙 공식 레포에 나와 있긴 하지만 자세하게 나와있진 않다.)
svg 타입 정의 파일을 만들어준다. CRA 타입과 동일하게 만들어 줬다. 나는 타입 정의 파일들은 따로 @types라는 폴더에 모아두고 있다. 그건 팀원간 컨벤션에 맞게 알아서 해보자.
// svg.d.ts
declare module '*.svg' {
import * as React from 'react';
export const ReactComponent: React.FunctionComponent<React.SVGProps<SVGSVGElement> & { title?: string }>;
const src: string;
export default src;
}
위에서 만든 svg 타입 정의 파일을 tsconfig.json 파일에서 include 필드에 포함시켜준다..
types 필드에 추가하지 않고 include 필드에 추가하는 이유는 이 링크를 참고하자
// pattern 형태(glob 패턴을 지원함)로 컴파일할 파일 또는 디렉토리 경로를 설정합니다. 일반적으로 include를 설정하지 않으면 프로젝트 루트 디렉토리부터 모든 typescript 파일을 컴파일합니다.
"include": [..., "svg.d.ts"],
// 혹은 d.ts 파일이 src 폴더 하위에 위치한다면
"include": ["src/**/*.{tsx,ts}"],
그러면 다음과 같이 사용 가능하다. url 혹은 react component로서 동시에 사용이 가능하다.
src를 콘솔을 찍어보면 해당 src 파일의 절대 경로가 찍히는 것을 볼 수 있다. 마찬가지로 이를 url 속성함수에서 활용할 수 있다.

import src, { ReactComponent as CustomSign } from '@assets/my-sign.svg';
const TheOther = () => {
...
console.log(src); // /src/assets/my-sign.svg
...
<article>
<img src={src} alt='sign' />
<CustomSign />
<div className='h-48 w-48 bg-no-repeat' style={{ backgroundImage: `url(${src})` }} />
</article>
...
public 폴더에서 이미지를 가져오는 것이 좋을까 src폴더에서 가져오는 것이 좋을까? 🤔❓
static 파일은 `public`폴더에 저장하는 것이 좋다.
왜냐하면 작업이 끝난 후, 리액트를 build하면 src폴더는 압축되지만 public 폴더는 그대로 보존하기 때문이다.
레퍼런스
1. 테일윈드css와 함께 리액트에서 원하는 배경 이미지를 적용하는 법