개발 기록 남기기✍️

[React] create-react-app 프로젝트에서 이미지 파일 로드하기 본문

Front-End/React

[React] create-react-app 프로젝트에서 이미지 파일 로드하기

너해동물원 2023. 3. 5. 22:26

CRA로 React 프로젝트를 시작하면 폴더 구조가 public, src로 나뉘어져 있는 것을 확인할 수 있다.

각 폴더의 역할은 무엇이고, 이미지 파일은 어느 폴더에서 관리하는 것이 좋을까?

또 jsx 파일 내에서 이미지 파일을 로드하는 방법은 무엇일까?

 

📁 public

  • 정적 파일을 관리하는 폴더 (index.html을 비롯한 html 파일, img 등)
  • webpack에 의해 관리되지 않는다. 파일이 후처리(post-process) 되거나 경량화(minify)되지 않고, build시 파일 원본이 그대로 build폴더에 복사된다.
  • public 폴더에 접근하기 위해서는 PUBLIC_URL 환경변수를 사용해야한다.
    (<img src={process.env.PUBLIC_URL + '/banner.png'} /> )
  • 경로가 잘못 되었거나 파일이 없을 경우 컴파일 단계에서 에러가 발생하지 않고, 404 에러가 발생한다.
  • css 파일이 아닌 jsx 파일에서만 public 폴더의 이미지를 로드할 수 있다.

 

📂 src

  • 개발하면서 작업하는 파일을 관리하는 디렉토리 (index.js, 그 외 리액트 컴포넌트 같은 js 파일, css 파일 등)
  • 파일을 찾지 못하는 경우, 컴파일 단계에서 에러를 잡을 수 있다.
  • import할 경우, 참조할 수 있는 경로(path) 문자열을 출력한다.
  • 서버 요청 횟수를 줄이기 위해 10,000 bytes 이하의 이미지는 path대신 data URL을 반환한다.
    (bmp, gif, jpg, jpeg, png 파일에만 적용, SVG 파일 제외)
    이 때, 파일 크기 기준(10,000 byte)은 IMAGE_INLINE_SIZE_LIMIT 환경변수로 설정을 변경할 수 있다.

 

🧐 public 폴더는 어느 때에 사용할 수 있을까?

  • 특정 이름을 가진 파일이 필요할 때
  • 이미지 파일이 수천 개 있어서 경로를 동적으로 참조해야 할 때
  • 번들링 된 코드 밖에서 pace.js 같은 작은 스크립트를 포함하고 싶을 때
  • webpack과 호환되지 않는 라이브러리를 사용해야 할 때 (<script> 태그로 라이브러리를 포함해야 할 때)

 

 

 

🖼️ jsx 파일 내에서 이미지 로드하기

📁 public

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

export default App;

이미지 파일을 public 폴더에 저장하면 src="/banner.png" 처럼 절대 경로로 작성하면 된다.

유의해야 할 점은 리액트로 만든 html 페이지를 배포할 때 yousunzoo.com 경로에 배포하면 아무런 문제가 없지만 yousunzoo.com/into/ 같은 경로에 배포하면 파일을 찾을 수 없다고 나온다.

 

그래서 리액트 공식 사이트는 예제 코드처럼 절대 경로 앞에다가 process.env.PUBLIC_URL을 붙여주는 것을 권장한다. 그럼 어떤 경로에서도 문제 없이 해당 파일이 잘 출력되는 것을 확인할 수 있다.

 

 

📁 src 

src에서 이미지를 로드하는 방법은 두 가지가 있다.

 

첫 번째) import

import banner from './banner.png';

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

export default App;

webpack을 사용하면 이미지 파일을 import하여 사용할 수 있다.

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

 

 

두 번째) require

function App() {
  return (
    <img src={require('./img/banner.png').default} className='site-banner' alt='site banner' />
  );
}

export default App;

node.js 환경이기 때문에 require로 문서 어디서나 파일을 불러올 수 있다. 이 방법을 사용하면 inline으로 src의 이미지 파일경로를 바로 지정할 수 있다.

 

require를 사용하면 객체 형태로 값이 리턴되기 때문에, 뒤에 default를 붙여서 경로가 문자열 형태 그대로 인식되게 만들어줘야 한다.

 

 

🖼️ 번외) css 파일 내에서 이미지 파일 로드하기

css파일에서 public 폴더에 접근하려고 하면 에러가 발생한다.

css파일에서 절대경로를 설정하면 src폴더를 기준으로 경로를 찾기 때문에 src폴더 내에서는 해당 파일을 찾을 수 없다.

 

src 폴더에 있는 이미지를 로드하려면, src 폴더를 기준으로 경로를 찾기 때문에 절대경로와 상대경로 둘 다 써도 무방하다.

background: url("./img/banner.png");
background: url("img/banner.png");

 

 

🧐 번외) Vite로 생성한 프로젝트에서 이미지 경로 불러오기

Vite로 생성한 프로젝트에서 img src를 작성하려면 기본적으로 import를 통해 파일 경로를 가져오지만, 다음과 같은 방법도 있다.

 

첫 번째) new URL

new URL을 사용하여 이미지 파일을 받아올 수 있다.

new URL('./banner.png', import.meta.url).href

 

import.meta.url은 현재 모듈의 url을 보여주는 기능이다. URL 생성자와 함께 사용하면 정적 파일의 전체 URL을 확인할 수 있게 된다.

위 코드는 로컬에서는 문제 없이 작동하지만, build 시에는 asset 폴더에 포함이 되지 않는다는 문제점이 있다.

import.meta.url은 브라우저와 Node.js 간 서로 다른 의미를 갖기 때문에, 이 패턴은 서버-사이드 렌더링(SSR)에 Vite를 사용하는 경우 동작하지 않는다. 또한 서버 번들은 클라이언트 호스트의 URL을 미리 결정할 수 없다.

 

 

두 번째) public 폴더에서 로드하기

🧐 public 폴더는 어느 때에 사용할 수 있을까?

  • robots.txt와 같이 소스 코드에서 참조되지 않는 에셋
  • 해싱 없이 항상 같은 이름을 갖는 에셋
  • 또는 URL을 얻기 위해 굳이 import 할 필요 없는 에셋

public 내의 파일들은 개발 시에는 / 경로에, 빌드 시에는 dist 폴더에 위치하게 된다.

public 디렉터리에 위치해 있는 에셋을 가져오고자 하는 경우, 항상 절대 경로로 가져와야만 한다.
( public/icon.png 에셋은 소스 코드에서 /icon.png으로 접근이 가능.)

public 디렉터리에 위치한 에셋은 JavaScript 코드로 가져올 수 없다.

 

 

세 번째) require-transform

vite-plugin-require-transform

 

vite-plugin-require-transform

A plugin for vite that convert from require syntax to import that compat for es module.. Latest version: 1.0.9, last published: a month ago. Start using vite-plugin-require-transform in your project by running `npm i vite-plugin-require-transform`. There a

www.npmjs.com

 

vite 플러그인 중 require를 사용할 수 있게 만드는 플러그인이다. CRA와 마찬가지로, require 뒤에 default를 붙여줘야 한다.

 

 


📚 참고