최근 사이드 프로젝트에서 웹팩을 직접 설정해보며, 웹팩의 다양한 속성들을 학습해보았다.
웹팩 설정을 하며 배운것들이 너무너무 많다.
웹팩 설정을 통해 할 수 있는 것들이 그렇게나 많다니..!
그 과정에서 특히 기억하고 싶은 publicPath와 historyApiFallback에 대해 기록해보려 한다.
✅ publicPath에 대해
`publicPath`는 브라우저가 번들링된 파일들(JavaScript, CSS, 이미지 등)을 어디서 찾아야 하는지 알려주는 기본 경로이다.
publicPath: '/'는 브라우저에게 모든 에셋을 서버의 루트 경로에서 찾아주라고 지시하는 것이다.
SPA에서는 일반적으로 `publicPath: '/'`를 사용하게 된다.
SPA는 클라이언트 측에서 라우팅을 처리하지만, 모든 라우트에서 하나의 동일한 HTML, JS파일을 사용하기 때문이다.
때문에 어떤 라우트에 있든, 클라이언트 측 라우터가 에셋 경로를 루트 경로로 올바르게 요청할 수 있는 것이다!
✔️ 문제) publicPath 설정이 없을 때 발생하는 오류
처음에 웹팩의 output 설정에서 publicPath를 지정하지 않고 프로젝트를 진행했다.
그 결과, 특정 경로에서 새로고침을 할 때 404 오류가 발생했다.
예를 들어, /movie/123 경로에서 새로고침을 하자 아래와 같은 오류가 발생한다.
publicPath가 설정되지 않으면, 기본값은 상대경로(./ 또는 "")이고, 이로 인해, bundle.js의 경로가 상대경로로 지정되어 있다.
때문에 브라우저는 http://localhost:3000/movie/bundle.js 경로에서 bundle.js를 찾으려고 한다.
루트 경로의 movie폴더에서 bundle.js파일을 찾는 것이다.
그러나 웹팩이 빌드한 bundle.js는 dist 폴더 내에 위치하기 때문에 잘못된 경로 요청을 하게되어 404 오류가 발생한다.
✔️ 해결) publicPath : "/" 설정
이 문제를 해결하기 위해 publicPath : "/" 설정을 추가하여 모든 에셋의 경로가 루트 경로('/')를 기준으로 로드되도록 처리해주었다.
모든 에셋의 경로가 루트 경로를 기준으로 하는 절대 경로가 되는 것이다.
※ publicPath: '/'에서 말하는 "루트 경로"란?
웹팩이 빌드를 후 생성된 정적 파일들이 위치한 dist폴더를 만한다.
- 빌드 전: app/src, app/public, webpack.config.js 등
- 빌드 후: app/dist/bundle.js, app/dist/index.html, app/dist/other-assets/...
publicPath: '/' 설정을하면, 개발서버는 dist폴더를 정적 파일을 서빙하는 루트 폴더로 설정한다.
즉, 웹팩에서 설정한 "publicPath : /"는 개발서버가 dist 폴더를 루트로 인식하고, 그 안에 있는 모든 에셋을 로드하라는 지시인 것이다!
때문에 어떤 라우트에서 새로고침을 해도 에셋을 안정적으로 로드할 수 있게 된다.
이제 `/movie/123` 페이지에서도 브라우저는 항상 루트 경로에서 에셋을 찾으므로
http://localhost:3000/bundle.js로 정확하게 파일을 요청하게 된다.
이렇게 어떤 라우트에서든 새로고침을 하더라도 올바른 경로에서 파일을 찾을 수 있게 되는 것이다.
✅ historyApiFallback 에 대해
위에서 spa의 특성으로 인해 publicPath 설정이 필요했는데,
historyApiFallback 설정도 spa의 특성과도 연관이 있다는 것을 알게되었다.
✔️ historyApiFallback란?
SPA에서 존재하지 않는 URL로 접근시, 404 대신 index.html을 제공하여, 클라이언트 사이드 라우팅이 정상적으로 작동하게 해주는 설정이다.
"/movie/123"과 같은 경로는 React Router같은 클라이언트 사이드 라우팅 경로고, 실제 서버에선 이 경로로 파일이 없다.
때문에 브라우저가 서버에 "/movie/123"경로를 요청하면, 서버는 404 에러를 일으키게 된다.
이때 historyApiFallback를 통해 404에러시 자동으로 index.html로 리다이렉트 시켜주는 것이다.
그러면 React앱이 다시 로드되고, React Router를 통해 현재 URL에 맞는 컴포넌트가 렌더링된다.
✔️ historyApiFallback와 publicPath
이렇게 historyApiFallback와 publicPath를 제대로 세팅해야 SPA 앱이 올바르게 리소스를 가져올 수 있게 된다.
- publicPath: '/' : 모든 에셋(JS, CSS, Html, 등)을 루트 경로 기준으로 로드
- historyApiFallback: true : 없는 경로 요청 시 index.html로 폴백 처리
1. 사용자: '/movie/123' 새로고침
2. 서버: 이 경로는 없는데? -> historyApiFallback 발동
3. 서버: index.html 반환
4. 브라우저: index.html 로드
5. index.html: publicPath='/'에 의해 루트 경로에서 모든 에셋 로드
6. React Router: '/movie/123' URL을 보고 해당 컴포넌트 렌더링
✅ 느낀점
웹팩이 단순히 번들러 역할을 넘어서, 파일 경로 문제까지도 해결할 수 있다는 것을 알게되었다.
특히 spa는 클라이언트 측 라우팅을 사용하다보니, 서버에서 리소스 로딩 방식을 직접 명시적으로 설정해줘야 함을 알게되었다!
이렇게 웹팩을 직접 구성해보면서, 앱이 작동되는 원리에 대해 좀 더 이해할 수 있는 계기가 된 것 같다.
https://webpack.kr/configuration/output/#outputpublicpath
https://webpack.kr/configuration/dev-server/#devserverhistoryapifallback
'프론트엔드' 카테고리의 다른 글
requestAnimationFrame를 활용해 애니메이션 최적화 해보자 (1) | 2025.02.02 |
---|---|
React-Query 사용기 (0) | 2024.10.20 |
FTP와 SFTP에 대해, RSA에 대해 (0) | 2024.10.04 |
css scope, scope 무시하기 (0) | 2024.09.22 |
Axios interceptor (1) | 2024.08.10 |