부트캠프에서 팀프로젝트로 진행한 맛이슈는 레시피를 공유하는 커뮤니티 서비스이다. 그렇다보니 한눈에 봐도 맛있어 보이는 레시피들을 썸네일로 보여줘야 하고, 더욱더 많은 유저들을 끌어 들이려면 SEO를 통한 검색엔진에 노출 되어야 유리하기 때문에 이미지 최적화와, SSR에 모두 장점이 있는 Next.js 기술을 사용하여 개발하였다.
맛이슈의 랜딩페이지는 다음과 같은 형태로 이루어져 있는데,
<헤더/>
<배너/>
<베스트 레시피/>
<카테고리1 레시피/>
<카테고리2 레시피/>
<카테고리3 레시피/>
<최신 레시피/>
<푸터/>
사실 프로젝트를 시작할때만 해도 기능구현에만 급급하고 성능이나 원리같은건 거의 모른채로 개발을해서 처음에는 랜딩페이지 전부를 SSR으로 처리하였었다. 그러다보니 페이지의 로딩시간이 너~무 길었다. 아무래도 페이지를 SSR하기 위해서 총 5가지 레시피 카테고리에 대한 API 요청이 들어가야하고, 해당 데이터를 응답 받은 후 또 S3서버에 이미지요청이 들어가고 다운받고 한꺼번에 렌더링하여 보여줘야 하기 때문인것 같았다.
const MainPageClient = ({bestRecipes,...})=> {
return (
<>
<Banner />
<div>
<MainBest initialData={bestRecipes} />
<MainCategory1 initialData={category1Recipes}/>
<MainCategory2 initialData={category2Recipes}/>
<MainCategory3 initialData={category3Recipes}/>
<MainNewest initialData={newestRecipes}/>
</div>
</>
);
};
이런식으로 서버컴포넌트에서 데이터를 프리패치 후 React-Query의 initialData기능을 활용하여 SSR하는 방식으로 구현했었다.
해결방법을 생각해본 결과, 페이지가 로딩되었을때 화면에 보이는 부분인 배너, 베스트 레시피까지는 SSR로 처리하고, 그 밑에 테마추천레시피들과 최신레시피 부분은 기본적인 골조만 Pre-Rendering하고 데이터는 React-Query를 활용하여 클라이언트 사이드에서 렌더링하는 방식으로 해결하였다. 그 덕분에 로드 시간은 1초 안으로 줄어들 수 있었다.
그러다가 최근에 원티드 프리온보딩 강의에서 코드 스플리팅이라는 개념을 배웠다. 코드 스플리팅은 페이지를 로드할때 JS들을 단일 파일에 담아서 다운받는데, 그것을 Chunk로 분할하여 화면에 미리 표시되야할 JS들부터 다운받고 상대적으로 중요하지 않는 JS들은 나중에 다운받아서 초기 로딩속도를 줄이는 기술이다.
Next.js에서는 Dynamic import라는 코드 스플리팅 하는 기능을 지원해주는데, 바로 적용해보았다. 기존에 먼저 화면에 노출되는 베스트 레시피는 서버컴포넌트에서 데이터를 프리페칭하여 SSR하였고, 나머지 컴포넌트들에게는 동적 임포트에 SSR설정을 false로 주어서 화면이 로딩된 후 렌더링 되게 하였다.
const MainPageClient = ({ bestRecipes }) => {
const MainCategory1 = dynamic(
() => import("..."),
{ ssr: false }
);
const MainCategory2 = dynamic(() => import("..."), {
ssr: false,
});
const MainCategory3 = dynamic(
() => import("..."),
{ ssr: false }
);
const MainNewest = dynamic(
() => import("..."),
{ ssr: false }
);
return (
<>
<Banner />
<div>
<MainBest initialData={bestRecipes} />
<MainCategory1 />
<MainCategory2 />
<MainCategory3 />
<MainNewest />
</div>
</>
)
}
이런식으로 기존의 SSR하던 컴포넌트를 dynamic import로 처리하고 데이터는 로딩후 react-query를 활용하여 추후에 클라이언트 사이드에서 패치하여 띄워주는 방식으로 변경하였다.
결과는 확실했다. 첫 화면 로드 속도는 698밀리초에서 386밀리초로 약 1.8배 개선되었다.
정리해보면 기존에는 랜딩페이지 전부를 SSR로 처리하여 페이지 로딩속도가 매우 느렸었는데, 첫 화면에 노출되는 베스트 레시피까지는 SSR로 처리고 노출되지 않는 테마 추천 레시피와 최신 레시피 부분은 동적 임포트를 통한 코드 스플리팅과 데이터들을 클라이언트 사이드에서 렌더링하는것으로 최적화하여 로드 속도를 개선할 수 있었다.
이번 프로젝트에서 성능 최적화 과정을 경험하면서, 초기 개발 단계부터 성능을 고려한 설계와 코드 작성의 중요성을 깨달았다. 또한 코드 스플리팅과 서버 사이드 렌더링 등 다양한 기술을 통해 성능 개선을 할 수 있는 방법들을 배웠는데, 앞으로는 성능 최적화를 더욱 고려하며, 사용자에게 좋은 경험을 제공할 수 있는 서비스를 개발하도록 노력해야 겠다.
프론트엔드 공부를 시작하고 기능을 구현하는것도 너무 재미있었는데, 퀄리티 있는 높은 코드를 작성하여 가독성과 유지보수성을 높이는 것도 재밌고, 이렇게 성능을 개선하고 결과물을 바로 확인할수 있는것도 모두 너무 재미있는것 같다.