만족

[React] 리액트 프로젝트 캐시 전략 본문

[React] 리액트 프로젝트 캐시 전략

FrontEnd/React Satisfaction 2022. 12. 18. 03:17

리액트 프로젝트를 빌드하면 나오는 결과물들을 간단히 다음과 같이 분류할 수 있다.

 

1. css

2. js

3. html

4. asset (png, svg ...)

 

이들에 관해 어떻게 캐시 전략을 세울 수 있을까?

 

css, js

css와 js는 빌드할때마다 결과물이 변경될 경우 파일네임 중간의 해시값이 바뀌게 된다.

 

예를 들어 처음 빌드했을 때 다음과 같은 빌드 결과물이 나왔다면,

 

js코드를 일부 수정하고 다시 빌드했을 때 

이런 식으로 js가 변경되었으므로 main.[HASH].js 에서 HASH가 업데이트된다.

 

따라서 같은 이름의 css, js는 다시 로드할 필요가 없고, 영구적으로 캐싱하기로 결정했다.

(빌드 결과물에서 직접 코딩하는게 아닌 이상... 어차피 빌드 파일 이름이 변경되므로 영구캐싱이 타당하다)

 

Header set Cache-Control "public, max-age=31536000"

 

max-age가 설정된 경우, 캐싱되어 있다면 만료시간이 도래하기 전에는 네트워크 요청을 아예 하지 않는다. (검증 안함)

 

html

html은 어떤 css, js, asset을 사용할 것인가?를 결정한다.

 

페이지에 진입할 때 html을 먼저 불러오고, 

이후 script, link 태그 등에서 css와 js를 로드한다.

 

만약 서버에서는 업데이트되었는데 클라이언트에선 html 파일이 캐싱되었고 그걸 그대로 사용한다면

사용자는 새로운 css, js 코드들을 사용할 수 없다.

 

따라서 캐싱을 허용하되, 사용할 때 반드시 서버에 검증하고 사용하도록 했다.

Header set Cache-Control "private, no-cache"
Header set Pragma "no-cache"

 

Pragma는 http 1.0 하위호환을 위한 것으로 생략해도 상관은 없다.

 

max-age vs private, no-cache

 

max-age만큼의 시간이 도래하지 않았다면 그 요청은 내부 캐시로 대체된다. (아예 네트워크 요청 안함)

 

private: 클라이언트에만 캐시를 허용한다.

no-cache: 캐시는 하지만 사용하기 전에 서버에 검증한다 (네트워크 요청으로 캐시를 검증하고, 무효할 경우 갱신)

 

가끔 must-revalidate, max-age=0, no-cache 조합을 사용하는 경우가 있다.

 

https://stackoverflow.com/questions/18148884/difference-between-no-cache-and-must-revalidate-for-cache-control

 

Difference between no-cache and must-revalidate for Cache-Control?

From the RFC 2616 http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1 no-cache If the no-cache directive does not specify a field-name, then a cache MUST NOT use the respons...

stackoverflow.com

요약하자면 http 1.1 버전 미만에서는 no-cache에 대한 호환성이 보장되지 않아,

하위 호환을 위해 이와 동일한 역할을 할 수 있는 max-age=0, must-revalidate를 같이 사용했던 것이다.

 

-> .혹자는 no-cache와 must-revalidate가 다른 동작을 한다고도 한다.

must-revalidate는 검증 시 서버가 5xx를 내려줄 경우, 오류를 반환하고

no-cache는 검증 시 5xx를 내려줄 경우 대신 캐시를 반환한다고 한다.

그러나 실험해본 결과 둘다 5xx가 내려올 경우 오류를 반환했다.

mdn 설명에도 명확하게 묘사되어있지 않아 어느 쪽이 확실한지는 모르겠다;

 

asset

파비콘, 이미지같은 파일은 자주 변경되지는 않겠지만

그래도 변경되기는 한다.

 

따라서 js/css처럼 max-age로 캐싱해서는 안되고, html과 동일하게 처리한다. 

Header set Cache-Control "private, no-cache"
Header set Pragma "no-cache"

 

다른 캐싱 전략: 버전 전략

html을 제외한 css, js, asset에 모두 max-age를 최대로 건다.

 

그리고 파일 이름에 버전을 붙인다.

 

예를 들어 logo.1.0.0.png라는 파일을 최대 기간 캐시한 다음,

버전이 올라가면 logo.1.1.0.png라는 새로운 파일이 지정되므로 새로 캐시한다.

 

이 방법도 쓸만하지만, 배포가 빈번한 프로덕션의 경우

배포할 때마다 일시적으로 트래픽이 증가할 수 있다.

(모든 파일들의 이름이 변경되므로 실제로 변경되지 않은 파일들의 캐시도 버려진다.)

 

얼마나 빨라졌나?

Network에서 Fast 3G 쓰로틀을 걸고 load time을 측정한다.

 

이전에는 모든 유형의 데이터에 대해 캐싱을 꺼놨었다.

(버그가 있는 예전 버전의 코드들이 배포되는 문제가 있었기 때문이다..)

 

react build output에서 가장 덩치가 큰 chunk js들이 많은 시간을 잡아먹고 있었다.

 

page load까지 평균 4~5초정도가 걸린다.

 

캐싱을 적용하면, 첫 방문에서는 캐시가 없으므로 똑같이 오래 걸리지만

이후부터는 캐시 조건에 일치하는 것들은 아예 네트워크 요청을 보내지 않거나 검증만 하게 된다.

 

따라서 로드 시간이 크게 줄어들었으며 

평균적으로 1~2초 내외로 page load가 끝난다.

 

 



Comments