[React] Create-react-app 프로젝트에서 이미지 경로를 설정하는 4가지 방법

차유림·2021년 8월 25일
57

create-react-app 프로젝트에서 이미지를 사용한다면
이미지가 public 폴더에 있는지 src폴더에 있는지,
또는 jsx파일에서 사용하는지 css에서 사용하는지에 따라
경로설정하는 방법이 달라 헷갈릴 수 있다.

따라서 어느 경우에 public, src 폴더에서 이미지를 관리하면 좋은지,
jsx, css에서 어떻게 이미지 경로를 설정하는지 방법을 정리해보려고 한다.

create-react-app으로 프로젝트를 생성했을 때의 기본 템플릿에서
이미지의 경로만 아래와 같이 수정한 후 진행했다.

🖼 어느 폴더에서 관리하는 게 좋은가?

📂 public

  • webpack에 의해 관리되지 않는다.
    (minify되지 않고, content hash가 포함되지 않는다)
    대신 원본이 build폴더에 복사된다.
  • public 폴더에 접근하기 위해서는 PUBLIC_URL 환경변수를 사용해야한다.
  • 경로가 잘못 되었거나 파일이 없을 경우 컴파일단계에서 에러가 발생하지 않고, 404 에러가 발생한다.👎
  • CRA 문서에서 다음과 같은 경우에만 public 폴더에서 관리하는 것이 유용하고, 이외에는 src 폴더 관리를 추천한다.
    • manifest.webmanifest 처럼 build된 결과물에서 특정한 파일 이름이 필요한 경우
    • 수천개의 이미지 파일을 동적으로 참조해야 하는 경우

📂 src

  • 파일을 찾지 못하는 경우, 컴파일 단계에서 에러를 잡을 수 있다.👍
  • import할 경우 참조할 수 있는 경로(path) 문자열을 출력한다.
  • content hash가 파일명에 포함되기 때문에 브라우저가 오래된 버전(파일 수정 전)의 파일을 캐싱하고 있는 경우를 고려하지 않아도 된다. (파일이 변경되었을 때만 hash값이 변경된다)👍
  • 서버 요청 횟수를 줄이기 위해 10,000 bytes 이하의 이미지는 path대신 data URL을 반환한다.
    (bmp, gif, jpg, jpeg, png 파일에만 적용, SVG 파일 제외)
    이 때, 파일 크기 기준(10,000 byte)은 IMAGE_INLINE_SIZE_LIMIT 환경변수로 설정을 변경할 수 있다.

🖼 jsx 에서 이미지 경로 설정

1. public 폴더에 있는 이미지

function App() {
  return (
    <img
      src={`${process.env.PUBLIC_URL}/public_assets/logo512.png`}
      className='App-logo'
      alt='React'
    />
  );
}

export default App;

파일을 못찾을 경우 컴파일 에러는 발생하지 않고 이미지가 깨진다.

public 폴더에 있는 이미지를 jsx에서 사용할 경우
공식문서에서는 환경변수의 PUBLIC_URL을 사용하라고 나와있지만
단순히 /이미지경로, 이미지경로 이런 식으로 지정해도 잘 불러왔다.

즉 아래 3가지 경로 다 가능
1. src={`${process.env.PUBLIC_URL}/public_assets/logo512.png`}
2. src={'/public_assets/logo512.png'}
3. src={'public_assets/logo512.png'}
4. src={'./public_assets/logo512.png'} 도 가능

2. src 폴더에 있는 이미지(import)

import logo from './src_assets/logo192.png';

function App() {
  return (
    <img src={logo} className='App-logo' alt='React' />
  );
}

export default App;

webpack을 사용하면 CSS 파일을 import 하는 것처럼 이미지 파일을 import하여 사용할 수 있다.
파일 최상단에서 사용하는 모든 이미지를 import하여 사용하는 동기적인 방법으로
webpack이 이미지 파일을 번들에 포함시킨다.
파일을 못찾을 경우 compile에러가 발생하여 코드를 작성할 때 수정할 수 있다.

  • import image path
    import logoPath from './src_assets/logo192.png'
  • image src 설정
    <img src={logoPath} />

3. src 폴더에 있는 이미지(require)

function App() {
  return (
    <img src={require('./src_assets/logo192.png').default} className='App-logo' alt='React' />
  );
}

export default App;

node.js 환경이기 때문에 require로 문서 어디서나 파일을 불러올 수 있다.
이 방법을 사용하면 inline으로 src의 이미지 파일경로를 바로 지정할 수 있다.
처음에 모든 이미지 파일을 import 하지 않아도 되기 때문에 편리해보인다.

<img src={require('./src_assets/logo192.png').default} />

✅ content hash, dataURL 확인

import logo from './src_assets/logo.svg';

function App() {
  return (
    <>
      <img src={require('./src_assets/logo.svg').default} className='App-logo' alt='React' />
      <img src={logo} className='App-logo' alt='React' />
    </>
  );
}

import 와 require 방식의 차이가 있을까 궁금하여 두 개의 img를 비교해보았다.
두 방식의 차이는 없었지만, logo192.png 파일의 경우 10,000byte이하여서 dataURL이 리턴된 것을 확인할 수 있었고, logo.svg 파일로 테스트했을 경우에 파일명 뒤에 동일한 content hash 값을 확인했다.

🖼 css 에서 이미지 경로 설정

🚧 public 폴더에 있는 이미지

Failed to compile ./src/App.css (./node_modules/css-loader/dist/cjs.js??ref--5-oneOf-4-1!
css파일에서 public 폴더에 접근하려고 하면 위와 같은 에러가 발생한다.
css파일에서 절대경로를 설정하면 src폴더를 기준으로 경로를 찾기 때문에
src폴더 내에서는 해당 파일을 찾을 수 없다는 에러였다.

그렇다면 public 폴더에 있는 이미지를 css파일에서 불러오는 방법은? 아직 못찾았다..
(craco를 사용해서 css-loader 설정을 변경하면 되는 것 같기도...)

꼭 public 폴더의 이미지를 적용해야 한다면 inline-style로 css를 적용할 수는 있다.
<div style={{ backgroundImage: 'url(/public_assets/logo512.png)' }}></div>

🚨 절대경로 설정시 루트 폴더 기준
jsx파일에서 절대경로는 public 폴더를 기준으로 한다.
css파일에서 절대경로는 src 폴더를 기준으로 한다.

🚧 CRA 이슈 정리

이와 관련해서 CRA 레포에도 이슈와 많은 댓글이 등록되어 있었다.
절대경로의 기준이 다르고, public 폴더의 이미지를 설정할 수 없어서 불편함을 느끼는 사람들이 있었지만, 결론은 src폴더에서 이미지를 관리하세요 였다.

9937번 이슈에서 atlanteh(Contributor)의 글을 정리하면 다음과 같다.

추가 정리 예정

    1. 처음에atlanteh가 scss에서 절대경로가 깨지는 이슈가 있어 이를 해결하였다.(CRA에 커밋-풀리퀘-머지 끝!)
    1. atlanteh은 public폴더에 이미지를 관리하지 않았기 때문에 이런 이슈를 몰랐다.

react-scripts@5.0.0-next.31 설치가 안되서 test 보류..
npm i react-scripts@5.0.0-next.31
Disable url resolving using the /* webpackIgnore: true */ comment

4. src 폴더에 있는 이미지

절대경로도 src 폴더를 기준으로 하기 때문에
아래처럼 상대경로, 절대경로 다 사용 가능하다.

background: url("./src_assets/logo192.png");
background: url("src_assets/logo192.png");

📚 참고

profile
🎨프론트엔드 개발자💻

1개의 댓글

comment-user-thumbnail
2021년 11월 17일

감사합니다!! 정말 큰 도움 되었어요🤩

답글 달기