프로젝트 도중 React로 만든 웹페이지의 초기 로딩을 개선하기 위해 React.lazy
을 활용한 Code Splitting을 적용하였습다. 이후 프로젝트를 진행하면서 변경사항을 수정하고 배포하였는데, 다음과 같은 에러가 발생하였습니다.
직역하면 Chunk 파일을 불러오지 못해서 발생하는 에러입니다.
Code Splitting을 적용하면 초기 페이지에서 불러와야 하는 번들의 크기가 줄어들어 로딩을 개선할 수 있습니다. 이후 페이지 이동 시 필요한 chunk 파일을 불러옵니다.
Code Splitting 적용 시 하나의 번들 파일을 chunk 파일로 나눕니다.예시로 다음과 같습니다.
main.js
|-- aaaa.chunk.js
|-- bbbb.chunk.js
|-- cccc.chunk.js
이후 앱에 변경사항이 생겨 다시 배포하게 되면 chunk 파일도 새로 생성되면서 파일명이 변경됩니다.
main.js
|-- xxxx.chunk.js
|-- yyyy.chunk.js
|-- zzzz.chunk.js
// 이전 버전의 파일들
// |-- aaaa.chunk.js
// |-- bbbb.chunk.js
// |-- cccc.chunk.js
이때, 사용자의 브라우저에서 캐싱이 되었거나, 이전 버전의 페이지가 계속 열려있던가 하는 등의 이유로 인해 지금은 존재하지 않는 이전 버전의 chunk 파일을 요청(위의 예시에서 aaaa.chunk.js 를 요청하는 등)하게 되면서 ChunkLoadError 가 발생합니다.
새로고침을 하게 되면 해결되는 것을 확인할 수 있었습니다. 이번 프로젝트에서는 React의 Error Boundary를 활용하여 새로고침을 통해 해결하였습니다.
다만, 에러 발생 시 새로고침을 하게 되면 chunk 에러를 제외한 다른 에러가 발생하였을 때 무한 새로고침에 빠질 수 있기 때문에, FallbackComponent에서 props로 넘겨받은 error의 message을 정규식을 통해 확인하여 ChunkLoadError가 발생하였을 때에만 새로고침 하도록 하여 해결하였습니다.
...
import { ErrorBoundary } from 'react-error-boundary';
function App() {
return (
<Wrapper>
<ErrorBoundary FallbackComponent={ErrorFallback}>
...
</ErrorBoundary>
</Wrapper>
);
}
interface ErrorFallbackProps {
error: Error;
}
const ErrorFallback = ({ error }: ErrorFallbackProps) => {
useEffect(() => {
const chunkFailedMessage = /Loading chunk [\d]+ failed/;
// props로 받은 error 확인하여 chunk error 발생 시 새로고침
if (error?.message && chunkFailedMessage.test(error.message)) {
window.location.reload();
}
}, [error]);
// chunk error 아니라면 에러 페이지 출력
return (
<div>
<h1>에러 발생. {error?.message}</h1>
</div>
);
};
export default App;
참고