React 앱 빌드 시 캐시를 지웁니다.

26095 단어 webdevjavascriptreact

어떤 문제를 해결하려고 합니까?



빌드가 생성되고 배포될 때마다 사용자는 앱에 적용된 새로운 변경 사항을 보기 위해 캐시를 지우기 위해 웹 페이지를 강제로 새로 고쳐야 합니다. 이것은 사용자에게 요청하는 실용적인 해결책이 아닙니다.

우리의 목표:



새 빌드를 생성하고 프로덕션에 배포할 때마다 페이지를 새로 고칠 때 사용자가 새 변경 사항을 볼 수 있는 솔루션을 원했습니다.

create-react-app을 사용하여 새로운 앱을 생성합니다. 앱 이름을 clear-cache-app로 지정하겠습니다.

npx create-react-app clear-cache-app
moment 라이브러리도 설치합니다. 나중에 그 중요성을 이해하게 될 것입니다.

cd clear-cache-app
npm i moment

모든 패키지가 설치되면 앱을 한 번 테스트 실행하십시오.

npm start
package.json 파일에서 파일 끝에 다음 코드를 추가합니다.

"buildDate": ""

새 파일을 생성합니다update-build.js . package.json 외에 기본 폴더에 있어야 합니다.update-build.js에는 다음 코드가 있습니다.

const fs = require("fs");
const filePath = "./package.json";

const packageJson = JSON.parse(fs.readFileSync(filePath).toString());
packageJson.buildDate = new Date().getTime();

fs.writeFileSync(filePath, JSON.stringify(packageJson, null, 2));

const jsonData = {
  buildDate: packageJson.buildDate,
};

const jsonContent = JSON.stringify(jsonData);

fs.writeFile("./public/meta.json", jsonContent, "utf8", function (error) {
  if (error) {
    console.log("An error occured while saving build date and time to meta.json");
    return console.log(error);
  }

  console.log("Latest build date and time updated in meta.json file");
});


새 빌드가 생성될 때마다 이 파일을 호출합니다. update-build.js에서 수행하는 작업은 크게 두 가지입니다.
  • epoch에서 현재 날짜/시간 값을 생성하고 있습니다.
  • meta.json 파일에서 해당 값을 업데이트하고 있습니다. 이 파일은 새 빌드가 생성될 때마다 자동으로 생성됩니다.

  • 이제 아래와 같이 package.json 파일에서 빌드 명령을 업데이트합니다.

    "build": "node ./update-build.js && react-scripts build",
    

    다음으로 withClearCache라는 HOC(higher-order Component)를 생성합니다. 우리의 주요 앱 구성 요소는 withClearCache에 대한 인수로 전달됩니다. 여기서 아이디어는 앱의 콘텐츠가 브라우저에 로드되기 전에 콘텐츠가 최신인지 여부를 확인해야 한다는 것입니다.

    다음 코드를 사용하여 src라는 이름의 ClearCache.js 폴더에 새 파일을 만듭니다.

    import React, { useState, useEffect } from "react";
    import packageJson from "../package.json";
    import moment from "moment";
    
    const buildDateGreaterThan = (latestDate, currentDate) => {
      const momLatestDateTime = moment(latestDate);
      const momCurrentDateTime = moment(currentDate);
    
      if (momLatestDateTime.isAfter(momCurrentDateTime)) {
        return true;
      } else {
        return false;
      }
    };
    
    function withClearCache(Component) {
      function ClearCacheComponent(props) {
        const [isLatestBuildDate, setIsLatestBuildDate] = useState(false);
    
        useEffect(() => {
          fetch("/meta.json")
            .then((response) => response.json())
            .then((meta) => {
              const latestVersionDate = meta.buildDate;
              const currentVersionDate = packageJson.buildDate;
    
              const shouldForceRefresh = buildDateGreaterThan(
                latestVersionDate,
                currentVersionDate
              );
              if (shouldForceRefresh) {
                setIsLatestBuildDate(false);
                refreshCacheAndReload();
              } else {
                setIsLatestBuildDate(true);
              }
            });
        }, []);
    
        const refreshCacheAndReload = () => {
          if (caches) {
            // Service worker cache should be cleared with caches.delete()
            caches.keys().then((names) => {
              for (const name of names) {
                caches.delete(name);
              }
            });
          }
          // delete browser cache and hard reload
          window.location.reload(true);
        };
    
        return (
          <React.Fragment>
            {isLatestBuildDate ? <Component {...props} /> : null}
          </React.Fragment>
        );
      }
    
      return ClearCacheComponent;
    }
    
    export default withClearCache;
    
    

    위 파일의 코드를 살펴보고 여기에서 정확히 무엇을 하고 있는지 살펴보겠습니다.
  • 콘텐츠에 액세스하기 위해 meta.json 파일에 API 호출을 하고 있습니다. 브라우저는 API 호출을 캐시하지 않으므로 파일이 캐시되더라도 항상 최신 응답을 받습니다.

  •    useEffect(() => {
          fetch("/meta.json")
            .then((response) => response.json())
            .then((meta) => {
              const latestVersionDate = meta.buildDate;
              const currentVersionDate = packageJson.buildDate;
    
              const shouldForceRefresh = buildDateGreaterThan(
                latestVersionDate,
                currentVersionDate
              );
              if (shouldForceRefresh) {
                setIsLatestBuildDate(false);
                refreshCacheAndReload();
              } else {
                setIsLatestBuildDate(true);
              }
            });
        }, []);
    
  • 위에서 볼 수 있듯이 응답에서 meta.json 파일에서 빌드 날짜를 얻습니다. buildDateGreaterThan 파일에서 생성된 최신 빌드 날짜와 meta.json 파일에서 가져온 캐시된 빌드 날짜의 두 인수를 허용하는 함수package.json에 해당 값을 전달합니다. 이 함수는 두 날짜/시간 값을 비교하여 최신 빌드 날짜가 캐시된 빌드 날짜보다 크면 true를 반환하고 그렇지 않으면 false를 반환합니다. 날짜/시간 비교를 위해 moment 라이브러리를 사용하고 있습니다.

  • const buildDateGreaterThan = (latestDate, currentDate) => {
      const momLatestDateTime = moment(latestDate);
      const momCurrentDateTime = moment(currentDate);
    
      if (momLatestDateTime.isAfter(momCurrentDateTime)) {
        return true;
      } else {
        return false;
      }
    };
    
    
  • 최신 빌드 날짜가 캐시된 빌드 날짜보다 크면 서비스 작업자 캐시, 브라우저 캐시를 삭제하고 하드 다시 로드를 수행합니다.

  • const refreshCacheAndReload = () => {
          if (caches) {
            // Service worker cache should be cleared with caches.delete()
            caches.keys().then((names) => {
              for (const name of names) {
                caches.delete(name);
              }
            });
          }
          // delete browser cache and hard reload
          window.location.reload(true);
        };
    
  • 최신 빌드 날짜와 캐시된 빌드 날짜가 동일한 경우 캐시를 지우지 않고 구성 요소를 로드합니다.

  • return (
          <React.Fragment>
            {isLatestBuildDate ? <Component {...props} /> : null}
          </React.Fragment>
        );
    

    이제 빌드 날짜와 시간을 표시하고 싶습니다. 생성된 빌드 날짜가 에포크이므로 날짜 형식을 dd-mm-yyyy hh:mm 형식으로 지정하는 데 도움이 되는 두 가지 유틸리티 함수를 만들었습니다.

    /**
     * Function returning the build date(as per provided epoch)
     * @param epoch Time in milliseconds
     */
    export const getBuildDate = (epoch) => {
      const buildDate = moment(epoch).format("DD-MM-YYY HH:MM");
      return buildDate;
    };
    

    마지막 단계는 App.js에서 캐시 지우기 구성 요소를 호출하고 내 UI에 빌드 날짜를 표시하는 것입니다. 내 App.js를 다음과 같이 업데이트했습니다.

    import React from "react";
    import logo from "./logo.svg";
    import "./App.css";
    import packageJson from "../package.json";
    import { getBuildDate } from "./utils/utils";
    import withClearCache from "./ClearCache";
    
    const ClearCacheComponent = withClearCache(MainApp);
    
    function App() {
      return <ClearCacheComponent />;
    }
    
    function MainApp(props) {
      return (
        <div className="App">
          <header className="App-header">
            <img src={logo} className="App-logo" alt="logo" />
            <p>Build date: {getBuildDate(packageJson.buildDate)}</p>
          </header>
        </div>
      );
    }
    
    export default App;
    
    

    그게 다야. npm run build 명령만 실행하면 빌드가 새 빌드 날짜 시간으로 생성됩니다.

    전체 소스 코드는 내 github repo에서 찾을 수 있습니다.


    ammartinwala52 / 지우기-캐시-반응-앱






    신용 거래:

    I want to give a shout out to Dinesh for his article on clearing the cache in react apps.

    I have taken the core idea of clearing the cache from his article. Do check it out.

    좋은 웹페이지 즐겨찾기