반응형
해당 글의 목적은 캐시 무효화란 무엇이고 어떠한 해결 방법이 있는지에 알아보기 위한 목적으로 글을 작성하였습니다.
1) 문제점 발생
💡 웹 브라우저에서 새로 배포를 하였는데도 이전 파일을 바라보고 있는 문제가 발생하였습니다.
이 문제는 브라우저 내에서 ‘강력 새로고침’ 혹은 ‘캐시 초기화’를 수행해야지만 이전 버전에 캐시가 사라지고 새로운 버전을 바라보아서 해결이 되었는데, 매번 변경 때마다 사용자 들이 ‘캐시 초기화’를 수행해야 하는 번거로움이 생겨서 이러한 작업 없이 수행 할 수 있도록 Cache Busting을 적용합니다.
2) Cache Busting
💡 Cache Busting 이란?
- Cache를 Busting(부수다, 고장내다) 라는 의미에 Cache Busting은 이전에 남아 있는 캐시로 인하여 새로 배포된 브라우져 혹은 이미지 등이 반영되지 않고 이전의 캐시 상태를 바라보고 있는 문제에 대해서 이를 해결하기 위한 동작을 의미합니다.
3) Bundler(Webpack)를 사용하는 환경에서 Cache Busting
💡 해당 방식은 파일 이름에 hash를 붙여주고 파일이 변경 될 때마다 이름 뒤에 hash 값이 변경되고 브라우저에서는 파일 변경 되었다고 인식하고 새로운 리소스를 받아서 화면에 보여주는 방식을 의미합니다.
💡 webpack과 같은 빌드 도구를 사용하는 경우에는 아래의 구문을 webpack.coifng.js 파일내에 이를 작성하면 쉽게 해결이 가능합니다.
output: {
path: path.join(__dirname, '/src/'),
filename: '[name].[chunkhash:8].js',
},
4) CRA(Create-React-App) 환경에서의 Cache Busting
💡 CRA로 개발환경을 구성한 경우 내부에 내장된 Bundler를 사용하기에 해당 내용을 직접적으로 수정이 불가능하여, 다른 방법을 찾아봤습니다.
1. Eject 명령어 수행하여 webpack 파일 수정
💡 CRA 내에서도 WebPack 파일을 수정하는 방법이 존재합니다.
이는 기존 Webpack을 이용하는 방법 외에 CRA를 이용하는 방법에서는 Eject 명령어를 통해서 해당 숨겨진 파일을 찾고 사용할 수 있습니다.
💡 CRA(Create-React-App)으로 프로젝트를 구성하면 종속된 라이브러리나 설정들이 숨겨져 있습니다. 이를 확인 및 수정하기 위해서는 eject 명령어를 사용하면 됩니다.
[더 알아보기]
💡 Eject 명령어란?
- 스크립트로 실행이 되며, 숨겨진 모든 설정(webpack, Bable, ESLint 등)을 밖으로 추출하는 명령어입니다. 해당 명령어는 한번 수행하면 되돌릴 수 없기 때문에 주의를 가지고 개발을 해야합니다.
[참고] eject 명령어를 수행하면 아래와 같이 폴더 구조가 변경됩니다.
[참고] eject 명령어를 수행하면 package.json 파일이 수정됩니다.
💡 그러나 CRA 공식사이트에서는 프로젝트 내에서는 eject 명령어 사용에 대해서 권장하지 않고 있습니다.
[참고] 공식사이트 - CRA 프로젝트 내에 eject 사용에 대한 언급
2. Meta 태그 내에 캐시 속성을 지정한 해결 방안
💡 해당 방식은 index.html 파일내에 meta 태그로 이를 추가하여서 캐시의 속성의 만료시간 혹은 캐시를 하지 않도록 처리하는 방안입니다.
<head>
<!-- Expires 속성 사용: 지정한 날짜까지만 캐시 유효 -->
<meta http-equiv="Expires" content="Sun, 07 Aug 2022 18:51:54 GMT">
<!-- Expires 속성 사용: 즉시 캐시 만료 -->
<meta http-equiv="Expires" content="0">
<!-- Cache-control 속성 사용: 캐시를 하지 않음 -->
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"/>
</head>
3. 파일 경로 뒤에 쿼리 스트링(Query String)을 이용한 해결 방안
💡 해당 방안 파일의 경로 뒤에 파라미터로 TimeStamp 값이나 식별자를 추가하는 방안을 의미합니다.
💡 이는 해당 페이지를 로드 하게 되면 다른 파라미터를 확인하고 새로운 버전을 가져오도록 처리하는 방식입니다.
[예시] .env 파일 내에 버전을 관리하는 상수를 지정합니다.
REACT_APP_SERVICE_VERSION=1.8.7
[예시] 페이지를 불러오는 경우 - 버전에 따라 처리를 하는 방식
{/* 환경파일에 지정한 버전 사용 */}
<script type="text/javascript" src={`${process.env.PUBLIC_URL}/index.css?v=${process.env.REACT_APP_SERVICE_VERSION}`}></script>
{/* 임의의 timestamp 값을 사용 */}
<script type="text/javascript" src={`${process.env.PUBLIC_URL}/index.css?time=${new Date().getTime()}`}></script>
4. 라이브러리를 이용한 해결방안
💡 해당 라이브러리를 사용하면 eject 명령없이 webpack 환경을 구성 할 수 있습니다. webpack과 같이 chunk 파일들 내에 hash 값을 넣어주어서 매번 동적으로 리소스를 다운받도록 수행합니다.
1. 라이브러리 설치
# npm을 이용한 설치
$ npm i react-app-rewired --save-dev
# yarn을 이용한 설치
$ yarn add react-app-rewired --dev
2. config-overrides.js 파일 구성
💡 해당 파일을 생성하고 아래와 같이 구성합니다.
module.exports = {
webpack: function (config, env) {
config.output.filename = 'static/js/[name].[hash:8].js';
config.output.chunkFilename = 'static/js/[name].[hash:8].chunk.js';
return config;
},
};
3. package.json 파일 수정
{
"scripts": {
// 변경 전
"start": "react-scripts start",
// 변경 후
"start": "react-app-rewired start",
}
}
[참고] 결과 화면
💡 bundler의 webpack 기능을 대체하여서 chunk 파일을 split하는 방법으로 아래와 같이 수행을 합니다.
5) CRA(Create-React-App) 공식 사이트에서 제안하는 해결 방안
💡 아래와 같이 캐시 버스팅(Cache Busting)과 관련되어 언급하고 있습니다.
Each file inside of the build/static directory will have a unique hash appended to the filename that is generated based on the contents of the file, which allows you to use aggressive caching techniques to avoid the browser re-downloading your assets if the file contents haven't changed. If the contents of a file changes in a subsequent build, the filename hash that is generated will be different.
[출처] https://create-react-app.dev/docs/production-build/#static-file-caching
💡 build/static 디렉토리 내의 각 파일에는 파일 내용을 기반으로 생성된 파일 이름에 고유한 해시가 추가되어 공격적인 캐싱 기술을 사용하여 파일 내용이 변경되지 않았습니다. 라고 이야기하고 있습니다.
💡 빌드하기 이전의 파일은 캐싱을 위한 hash 값이 들어가 있지 않고, 빌드 이후에는 고유한 해시가 추가 된다라고 이야기하고 있습니다.
[공식사이트] 해결방안
To deliver the best performance to your users, it's best practice to specify a Cache-Controlheader for index.html, as well as the files within build/static.
💡사용자에게 최고의 성능을 제공하려면 index.html과 build/static 내의 파일에 대해 Cache-Control를 header에 지정하는 것이 가장 좋습니다.
Using Cache-Control: max-age=31536000 for your build/static assets, and Cache-Control: no-cache for everything else is a safe and effective starting point that ensures your user's browser will always check for an updated index.html file, and will cache all of the build/static files for one year.
💡 빌드/정적 자산에 대해 Cache-Control: max-age=31536000을 사용하고 다른 모든 자산에 대해 Cache-Control: no-cache를 사용하는 것은 사용자의 브라우저가 항상 업데이트된 index.html 파일을 확인하도록 하는 안전하고 효과적인 시작점입니다. 모든 빌드/정적 파일을 1년 동안 캐시합니다.
해결방안을 응용하여 index.html 파일내에 해당 소스코드를 적용합니다.
<head>
<meta http-equiv="Cache-Control" content="max-age=31536000" />
<meta http-equiv="Cache-Control" content="no-cache" />
</head>
[참고] 공식사이트 - Static File Caching
6) [참고] 동적 이미지 캐시 무효화
💡 해당 앱에서 발생하는 문제 뿐만 아니라 이미지에서도 이전에 사진을 바라보는 문제가 발생했던 적이 있습니다.
💡 이에 대해서 이미지의 변경이 발생하여도 URL 뒤에 time=이라는 파라미터를 붙여서 매번 새로운 이미지로 인식하여서 가져와서 해결하는 방법이 있었습니다.
const userProfileImageUrl = `${PROFILE_URL}/${userSq}.png?time=${new Date().getTime()}`;
오늘도 감사합니다😀
반응형
'React & React Native > 이해하기' 카테고리의 다른 글
[RN] React Native Android Studio 디버깅 이용방법: Logcat, Profiler, App Inspection (0) | 2023.10.25 |
---|---|
[RN] React Native 빌드 캐시 초기화 및 최신 버전 설치 명령어 : react-native-cli, yarn, watchman, metro, gradle, adb (0) | 2023.09.11 |
[React] router / router-dom v5 → v6 버전 업 이해하기 (2) | 2022.06.29 |
[React] 함수형 컴포넌트 생명주기(lifecycle) 이해하기 (2) | 2022.06.12 |
[React] 클래스 컴포넌트 생명주기(lifecycle) 이해하기 (0) | 2022.06.06 |