React
성능 최적화 (Cache Busting)
🔎 웹 캐시 (브라우저 캐시)
웹 페이지는 많은 파일들과 이미지들로 구성되어 있다. 당장 네이버 를 들어가서 관리자 모드(F12) 를 눌러서 Network 를 확인해보면 수많은 파일들을 읽어오고 있는 것을 볼 수 있다.
하지만 저 수많은 파일들 중 하루에 한번이라도 수정이 일어나지 않는 파일이 얼마나 될까? 자신있게 거의 대부분이라고 말할 수 있을 것 같다. 그렇다면 매번 페이지를 새로고침할 때마다 저 파일들을 읽어온다면 시간이 낭비될 것이다. 하지만 다행히 웹 브라우저는 캐시를 가지고 있다. 이미지나 js, css 파일들을 읽어 올 때 respone header 에 설정한 cache-control 데이터를 활용하여 cache 에 남겨놓고 다음번 호출 시에는 브라우저가 기억하고 있는 cache 에서 데이터를 바로 가지고 오는 것으로 대체한다.
하지만 이러한 cache 에도 단점이 있으니... 변경이 되었다는 걸 브라우저가 인식하지 못하면 (같은 파일명) 실제론 수정이 되었어도 브라우저는 자신이 기억하고 있는 데이터를 사용하고 따로 해당 파일을 server 에 요청하지 않는다. 그리고 이러한 특성은 react 와 같은 SPA 에서는 치명적이다.
🔎 SPA 와 Cache
SPA 는 브라우저가 server 에 페이지에 대한 요청을 하면 index.html 을 응답으로 준다. 이 index.html 은 head 외에 body 는 비었는데 번들링 된 js 파일을 바탕으로 동적으로 page 가 로딩된다. 만약 SPA 페이지가 수정 되면 build 시 번들링 된 js 파일은 새로 만들어진다. 하지만 브라우저에서 이를 인식 못한다면 변경 전의 js 파일을 캐시를 통해 가져와 사용하게 되기 때문에 수정사항이 반영이 안 될 수 있다. (실제 반영 되었지만 사용자 입장에서는 수정전의 데이터를 볼 수 있다.)
위 페이지에서 '우버현황' 을 '후버현황' 으로 수정한 후 어떻게 보이는지를 확인 해 보자.
위에 보이는 대로 home.chunk.js 파일은 실제 수정이 되었지만 브라우저는 cache 된 chunk.js 파일을 사용하였기 때문에 그대로 '우버현황' 으로 보이고 있다.
이러한 오류를 방지하기 위해 가장 간단한 방법은 cache-control 부분에 no-cache 를 사용하여 항상 server 에 요청할 수 있다. 하지만 개발단계라면 모를까 운영중인 페이지에 수정이 빈번하게 발생하지 않는데 매번 새로운 js 파일과 이미지, css 파일을 불러온다면 성능이 떨어지게 된다. 그래서 cache 를 사용하면서도 수정 시에는 변경된 내용을 보여줄 수 있는 cache busting 기법에 대해 알아보도록 하자.
🔎 Cache Busting
서두에 브라우저에서 cache 된 데이터를 가지고 온다고 할 때 조건이 있었다. 바로 동일한 파일을 가져올 때 cache 에 남아있다면 cache 에 있는 데이터를 사용한다고 하였다. 번들링된 파일이 수정이 일어날 때 다른 파일명으로 저장한다면 cache와 상관없이 수정된 최신버전의 파일을 불러오게 될 것이다. 이러한 기법이 cache busting 이다.
// webpack.config
{
...,
output: {
publicPath: '/',
filename: '[name].[contenthash:8].js',
chunkFilename: '[name].[contenthash:8].chunk.js',
path: path.resolve(__dirname, 'dist'),
clean: true,
},
...
}
webpack.config 파일 내 filename 과 chunkFilename 에서 [contenthash:8] 을 추가하였다. 이렇게 되면 webpack 에서 build 시 번들링된 파일을 생성할 때 hash 값의 8자리를 파일명에 추가로 붙여주어 수정전과 파일명이 달라지게 된다.
위와 같이 페이지에 수정이 발생했을 경우 번들링된 파일에 hash 값이 변경되고 (home.chunk.js 참고) 새로고침 시 변경된 파일을 새로 가져와서 수정된 페이지가 보이게 된다.
🔎 성능최적화
cache busting 을 사용하여 실제 변경이 발생하였을 때 번들링 된 js 파일의 파일명이 변경되고 이를 통해 브라우저가 변경을 감지할 수 있기 때문에 이러한 경우를 제외하면 항상 캐시된 js 파일을 불러오는 것이 웹페이지 성능 개선에 도움이 된다. 따라서, Cache-Control 을 통해 max-age를 최대한 (1년) 으로 설정하여 성능을 최적화 하였다.
// nginx.conf
server {
// ...
location ~* \.(?:css|js)$ {
expires 1y;
access_log off;
add_header Cache-Control "public";
}
// ...
}
요약
Nginx - Cache-Control max-age 최대 (1년)
React - Cache Busting (webpack)
수정이 발생하였는지 cache busting을 통해 감지,
수정이 없을 경우 항상 cache를 통해 성능 향상