[React] ChunkLoadError 해결

기록저장소·2024년 1월 12일

배포를 진행하면 빌드 과정에서 코드 분할로 Chunk 파일이 재생성되는데, 배포 전부터 사용하던 사용자는 Chunk 파일을 불러오지 못하거나 변경되어 서비스에서 오류가 발생한다.
이러한 문제를 해결하려고 한다.

원인

웹팩 설정을 따로 하지 않으면 JS파일들이 청크파일로 나누어지면서 새로운 해시값을 부여받는다.
배포 시, 서버에는 위와 같은 이유로 새로운 파일들이 배포되어 있는 상태입니다.
이 상태에서 배포하기 이전에 서비스를 사용하고 있던 사용자들은 이전 파일명을 서버에 요청한다.

💣 이전 파일명을 가진 파일이 없다 보니 에러가 발생한다.

해결 방안

  1. 서버에서 이전 파일들의 리소스를 지우지 않고 관리
    • 서버 자원을 사용하고 이전 파일 리소스들을 관리해줘야 함
  2. Service Worker를 사용하여 페이지 로딩 시 Chunk 파일들을 모두 로딩하여 캐싱
  3. React Error Boundary 등을 활용하여 사용자가 업데이트를 인지할 수 있는 페이지로 안내
    • 사용자가 에러를 인지하고 업데이트를 수동으로 확인하려면 페이지를 새로고침해야 한다. 자동으로 업데이트를 알리는 방법은 별도로 구현해야 함. 해당 방법으로 많이 사용하지만 별도로 구현해야하는 양이 적은걸 지향하여 채택안함
  4. 파일을 동적으로 로드할 때 에러가 발생하면 새로고침
    • 무한 리프레시가 되지 않도록 처리해야 함 (해당 방법으로 채택)

적용

// lazyWithRetry.ts
export const lazyWithRetry = (componentImport: () => any) =>
    lazy(async () => {
        const pageHasAlreadyBeenForceRefreshed = JSON.parse(
            window.localStorage.getItem('page-has-been-force-refreshed') || 'false'
        );

        try {
            const component = await componentImport();

            window.localStorage.setItem('page-has-been-force-refreshed', 'false');

            return component;
        } catch (error) {
            if (!pageHasAlreadyBeenForceRefreshed) {
                // Assuming that the user is not on the latest version of the application.
                // Let's refresh the page immediately.
                window.localStorage.setItem('page-has-been-force-refreshed', 'true');

                return window.location.reload();
            }

            // The page has already been reloaded
            // Assuming that user is already using the latest version of the application.
            // Let's let the application crash and raise the error.
            throw error;
        }
    });
// module.ts
import { lazyWithRetry } from '@static/js/lazyWithRetry';

const Main = lazyWithRetry(() => import('@pages/index'));

참조사이트

React + Webpack: ChunkLoadError: Loading chunk X failed.

profile
기록을 남기는 공간.

0개의 댓글