일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- framer
- 테오의 스프린트
- framer-motion
- 시스템디자인
- 회고
- useState
- Effective Typescript
- 개발자 원칙
- ASP.NET
- 캐나다개발자
- CSS
- 캐나다취준
- TS
- 이펙티브타입스크립트
- VS Code
- 알고리즘
- 타입스크립트
- 코드트리
- JSBridge
- 글또
- Semantic Versioning
- SemVer
- React-Router-Dom
- 글또 10기
- typescript
- Framer motion
- CSS방법론
- JUNCTION2023
- react
- 개발자를 위한 글쓰기 가이드
- Today
- Total
큰 꿈은 파편이 크다!!⚡️
리액트 앱 배포 후 Cache 문제 🧹 삽질기 본문
꽤 영향력이 있는 문제를 수정한 뒤 리액트 앱을 배포했을때, 업데이트된 내용이 보이지 않는다는 피드백을 듣고는 식은땀이 났던 기억이 있다. 당시 급하게 문제를 해결한 뒤 다시는 발생하지 않을 것이라 생각했는데 같은 피드백을 또한번 마주하게 되어 캐시로 인해 두 번의 고통을 겪은 경험을 공유해보려 한다.
개발환경
- React
- Typescript
- Webpack5
- IIS
📌 캐싱Caching이란?
웹사이트 접근 시 로드하는 여러 리소스(css, js, 이미지파일 등)를 ‘캐시Cache’로 저장하여, 추후 해당 페이지에 재방문했을 때 리소스 로딩 속도를 줄이는 기법
문제 1. 항상 main.js
를 사용한다
처음 겪었던 문제의 원인은, index.html
의 <script link=”main.js” />
에서 호출하는 js파일의 이름이었다. 업데이트한 main.js
와 내용은 달라도 같은 파일이름을 사용하다보니, 브라우저는 동일한 파일로 인식하여 다시 로드하지 않는다. 당연하게도 브라우저 새로고침이나 컴퓨터 껐다 켜기 등의 민간요법은 효과가 없다. 모든 사용자에게 연락하여 Shift + F5(강력한 새로고침)를 하세요.. 라고 할 수도 없는 노릇이니..
그렇다면 어떻게 해야 할까? 번들러로 사용중인 웹팩에서는 chunkhash
또는 contenthash
라는 해쉬 값을 사용할 수 있다.
📌 Chunk hash
entry를 기반(chunk별로)으로 해쉬를 갖는다. 변경이 일어난 entry의 해쉬가 바뀐다.
📌 Content hash
변경된 파일의 content를 기반으로 해쉬를 갖는다. 변경된 파일의 해쉬가 바뀐다.
해쉬 값을 output 파일에 붙여, 호출하는 스크립트 파일의 이름을 바꿈으로서 브라우저가 파일이 다름을 인식하게 하고, 파일을 다시 로드하도록 했다. 나의 경우는 chunkhash
를 사용했다. 웹팩 공식 문서의 캐싱 항목에서도 캐시 문제 처리를 위해 해쉬 값을 사용하여 파일 이름을 변경한다는 것을 확인할 수 있다.
entry: {
main: "./src/index.tsx",
},
output: {
filename: "[name].[chunkhash:8].js",
path: path.join(__dirname, "build"),
publicPath: "/",
assetModuleFilename: "images/[hash][ext][query]",
},
문제2. Cache control 설정
이렇게 캐시 문제는 해결된 줄 알았으나 최근에 캐싱이 원인으로 보이는 문제가 다시 나타났다. 내 PC에서는 안그렇고, 다른 누군가의 PC에서는 발생하는 문제여서 더 당황스러웠다. 🤯 이미 해쉬값을 사용해서 배포할때마다 파일 이름을 바꾸는 작업은 하고 있었고, 원래 없던 문제였기에 나는 상상력을 동원하여 가설을 세워보았다.
의심 1. 크롬에 로그인해있으면 계정이 캐싱한다??
의심 2. package.json 버전업을 안했따??
의심 3. 지금까지는 이런 일이 없었는데 이제 발생했다는건.. 크롬이 뭔가 업데이트되었다??
😵 가설을 토대로 파워 구글링을 해보았으나 당연히 아니었고, 특히 의심3은 응 아니야 로 빠르게 결론을 내렸다.
Chrome serves the most requested resources from the memory cache, which is very fast, but is cleared when the browser is closed.
ㅡ https://developer.chrome.com/docs/lighthouse/performance/uses-long-cache-ttl/
😵 계속 찾다보니 다른 내용은 모르겠고 아래와 같은 문장이 눈에 띄어 cache-control을 no-cache
로 설정하면 되는 것이구나, 생각했다. 이 미디엄 글을 보고 E tag라는 것을 막 알게 되었기에 성급하게 내린 결론이었다.
For ETags to be used and the browser to send the If-Modified-Since and If-None-Match headers, the cache control must be set to no-cache.
ㅡ https://stackoverflow.com/a/68407563
추론은 잘못되었을지 모르겠지만 no-cache
설정은 결론적으로 매우 타당해 보였고, 실제로 문제를 해결해주었다.
📌 Cache control: no-cache
”캐싱하지 말라” 가 아닌, 캐싱된 내용을 사용하기 전에 서버에 내용이 같은지 확인 후 사용하라는 의미
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
잠깐!!! 🤔
그런데 이 글을 쓰기 위해 정리를 하다보니 의문이 들었다.
문제되는 당시의 요청 헤더를 보면 아래와 같이 cache-control: max-age=0
으로 설정되어 있다.
max-age = 0
은, HTTP 1.x에서는 no-cache
가 지원되지 않기 때문에 workaround로 사용할 수 있는 설정이라고 한다. 하지만 그렇다면 이 설정이 문제가 안되었어야 맞는 게 아닌가? 🤔 일반적인 검색만으로는 시원한 답을 찾을 수가 없었다.
🧠 아래는 오직 MDN만을 토대로 결론내린 내 생각이다. 언젠가 확실한 답을 알게된다면 수정해봐야겠다.
max-age=0 is a workaround for no-cache, because many old (HTTP/1.0) cache implementations don't support no-cache. Recently browsers are still using max-age=0 in "reloading" — for backward compatibility — and alternatively using no-cache to cause a "force reloading".
⇒ 최근 브라우저는 max-age=0
을 “realoading”, no-cache
를 “force reloading”으로 인식한다. 그러니 max-age=0
은 HTTP 1.x 호환을 위해서만 사용하는 것이 맞지 않을까??
Typically, must-revalidate is used with max-age.
⇒ max-age
설정을 사용하면 must-revalidate
설정을 함께 사용하는 것이 보편적이다. 나의 경우는 max-age
만 설정되어 있었기에 문제가 있었던 것이 아닐까..?
보너스. IIS 사용자들을 위한 설정 방법
IIS서버를 사용하고 있었기 때문에 IIS Manager → HTTP Response Headers → Actions - Set Common Headers를 누르면 설정 팝업이 열린다. 두 번째 체크박스 Expire Web content - Immediately를 설정한다. 캐시 컨트롤도 서버 쪽에서 수정해야 하는 부분이었다!
마무리
결론은 설정 체크박스 활성화로 싱겁게 끝났지만 나는 아직 웹과 서버 간의 역할, 그리고 배포와 관련된 인프라나 구성 등을 잘 이해하지 못하고 있다고 느꼈다. 캐시 컨트롤은 클라이언트에서 할 수도 있지 않을까?? 생각해서 이것저것 더 찾아봤던 것 같다.
아무튼 이 삽질을 계기로 웹을 배포할 때 어떤 부분들을 고려해야할지 또 새로운 점을 깨달을 수 있었다. 너무 강렬했던 기억이었기에 잊기는 쉽지 않을 것이다 ^^
References
https://medium.com/@codebyamir/a-web-developers-guide-to-browser-caching-cc41f3b73e7c
https://mohamedradwan.com/2010/12/26/caching-static-files-js-files-css-and-images-in-iis-7/
'Web FE' 카테고리의 다른 글
SSR 개발 중 만난 실전 디자인 패턴 PRG (ft. ASP.NET) (0) | 2023.04.09 |
---|---|
리액트 성능 향상 첫걸음: useMemo, useCallback, React.memo (0) | 2023.03.12 |
이펙티브 타입스크립트 🦅 2장 (3) (0) | 2022.10.08 |
이펙티브 타입스크립트 🦅 2장 (2) (0) | 2022.09.28 |
이펙티브 타입스크립트 🦅 2장 (1) (0) | 2022.08.28 |