React에서 이미지(images) 경로 설정 방법
React에서 이미지를 사용해야 할 때 해당 이미지가 public폴더에 있는지 src폴더에 있는지, 또는 jsx파일에서 사용하는지 css에서 사용하는지에 따라 경로 설정하는 방법이 달라 처음 경로를 설정할 때 혼란스러운 경험이 있을 수 있습니다.
React에서 이미지를 사용하는 방법을 정리해 보았습니다.
어느 폴더에서 관리하는 게 좋은가?
📂 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을 사용하라고 나와있지만
단순히 /이미지경로, 이미지 경로 이런 식으로 지정해도 호출이 가능합니다. 다만 Github에 소스코드를 올릴 경우에는 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에러가 발생하여 코드를 작성할 때 수정할 수 있습니다.
- 방법1) import image path
=> import logoPath from './src_assets/logo192.png' - 방법2) 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 이슈 정리
- #9937 public directory css url
- #10022 CRA 4 fails to compile when css background-image ulr('url') not resolved
이와 관련해서 CRA 레포에도 이슈와 많은 댓글이 등록되어 있습니다. 절대 경로의 기준이 다르고, public 폴더의 이미지를 설정할 수 없어서 불편함을 느끼는 사람들이 있었지만, 결론은 src폴더에서 이미지를 관리하라는 게 주요 내용이었습니다.
src 폴더에 있는 이미지
절대 경로도 src 폴더를 기준으로 하기 때문에 아래처럼 상대 경로, 절대 경로 다 사용 가능합니다.
background: url("./src_assets/logo192.png");
background: url("src_assets/logo192.png");