Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
과제 체크포인트
배포 링크
https://jheejindev.github.io/front_6th_chapter4-1/react/
https://jheejindev.github.io/front_6th_chapter4-1/vanilla/
기본과제 (Vanilla SSR & SSG)
Express SSR 서버
<!--app-html-->,<!--app-head-->)서버 사이드 렌더링
클라이언트 Hydration
window.__INITIAL_DATA__스크립트 주입Static Site Generation
심화과제 (React SSR & SSG)
React SSR
renderToString서버 렌더링React Hydration
Static Site Generation
구현 과정 돌아보기
가장 어려웠던 부분과 해결 과정
그동안 Next.js를 쓸 때 SSR을 그냥 “이럴 때 쓰는 거구나”, “이렇게 쓰면 되네” 정도로만 이해하고 있었습니다.
사실 서버랑 클라이언트가 어떤 과정을 거쳐서 화면을 만들어내는지는 깊게 고민해본 적도 없었고, 그냥 Next.js가 편하게 제공해주는 기능 중 하나라고만 생각했던 것 같습니다.
그런데 이번 과제를 하면서 단순히 결과만 얻는 것과, 그 결과가 만들어지는 과정을 이해하는 건 전혀 다른 문제라는 걸 깨달았습니다. SSR의 구조와 원리를 하나하나 따라가 보니, 제가 얼마나 겉핥기 식으로만 접근했는지를 알게 됐고, 동시에 더 깊은 이해가 필요하다는 점도 크게 느꼈습니다.
그래서 이번 과제에서 가장 어려웠던 부분은 SSR의 전체적인 동작 과정을 파악하는 것이었습니다.
단순히 코드를 짜는 걸 넘어서, 서버에서 HTML이 생성되고 클라이언트에서 Hydration이 이어지는 흐름을 제대로 이해하는 게 정말 쉽지 않았습니다.
특히 발제를 보면서 이 정도로 이해가 안 된 적은 처음이었는데, 무려 네 번이나 다시 봤지만 결국 머릿속에 남은 건 준일 코치님의 코딩 실력에 대한 감탄뿐이었습니다.
이번 경험 덕분에 단순히 "쓰는 법"이 아니라 "왜 그렇게 동작하는지"를 이해하는 게 얼마나 중요한지 다시 돌아보게 된 것 같습니다.
SSR 동작 과정 단계별 이해
사용자가 URL에 접근하면 서버가 먼저 요청을 받고, 해당 URL에 맞는 데이터를 준비해야 한다.
서버에서 미리 데이터를 가져와서 스토어에 저장해야 클라이언트에서도 동일한 상태를 유지할 수 있다.
React 컴포넌트가 실제로 HTML 문자열로 변환되는 과정을 직접 경험했습니다. 이 과정에서 컴포넌트의 모든 상태가 HTML에 반영되어야 한다는 것을 깨달았습니다.
서버에서 준비한 데이터를 클라이언트로 전달하기 위해 window.__INITIAL_DATA__에 주입하는 것이 핵심.
클라이언트에서는 서버로부터 받은 HTML과 데이터를 사용해서 React 앱을 활성화(혹은 연결) 시키는 과정이 Hydration이다.
구현하면서 새롭게 알게 된 개념
useSyncExternalStore의 getServerSnapshot의 중요성
useSyncExternalStore의 세 번째 인자인 getServerSnapshot이 하이드레이션 불일치를 방지하는 핵심이라는 것을 알게 되었습니다. 서버에서 렌더링된 상태와 클라이언트에서 초기 상태가 정확히 일치해야 React가 하이드레이션을 성공적으로 수행할 수 있습니다.
ServerRouter와 Client Router의 차이점
서버에서는 브라우저 히스토리 API가 없기 때문에 push 메서드가 실제로는 URL을 변경하지 않고 단순히 라우트 매칭만 수행한다는 것을 알게 되었습니다. 서버 사이드에서는 네비게이션이 불가능하고, 오직 URL 파싱과 라우트 매칭만 가능합니다.
성능 최적화 관점에서의 인사이트
SSG 배치 처리로 메모리 효율성 확보
성능 인사이트: 전체 상품(수만 개)을 한 번에 SSG로 생성하면 메모리 부족이 발생할 수 있어서, 선택적 배치 처리를 도입했습니다. 인기 상품 31개만 선별하여 생성함으로써 빌드 시간을 단축하고 메모리 사용량을 최적화했습니다.
학습 갈무리
Q1. 현재 구현한 SSR/SSG 아키텍처에서 확장성을 고려할 때 어떤 부분을 개선하시겠습니까?
상태 관리 아키텍처의 중앙화
개선 방안:
캐싱 전략의 부재
개선 방안:
Q2. Express 서버 대신 다른 런타임(Cloudflare Workers, Vercel Edge Functions 등)을 사용한다면 어떤 점을 수정해야 할까요?
현재 코드에서 fs, path, crypto 등을 사용하고 있는데, 이들을 Web Standard API로 대체해야 합니다.
Cold Start 최적화
Q3. 현재 구현에서 성능 병목이 될 수 있는 지점은 어디이고, 어떻게 개선하시겠습니까?
동기적 데이터 페칭
main-server.tsx에서 Promise.all을 사용하고 있지만, 캐싱이 없어서 매 요청마다 API를 호출합니다.
카테고리 정보는 자주 변경되지 않으므로 Redis나 메모리 캐시를 도입해서 5분 정도 캐싱하면 API 호출 횟수를 크게 줄일 수 있을 것 같습니다.
Q4. 1000개 이상의 상품 페이지를 SSG로 생성할 때 고려해야 할 사항은 무엇입니까?
빌드 시간 관리
메모리 관리
증분 빌드
CDN 캐시 관리
Q5. Hydration 과정에서 사용자가 느낄 수 있는 UX 이슈는 무엇이고, 어떻게 개선할 수 있을까요?
Hydration Mismatch로 인한 깜빡임 현상
UX 이슈: 서버에서 렌더링된 HTML과 클라이언트 상태가 다를 때 React가 DOM을 다시 렌더링하면서 깜빡임 발생
개선 방안
인터랙션 차단 시간
UX 이슈: 하이드레이션 완료까지 사용자가 버튼 클릭이나 입력을 할 수 없음
개선 방안
Q6. 이번 과제에서 학습한 내용을 실제 프로덕션 환경에 적용할 때 추가로 고려해야 할 사항은?
모니터링 및 로깅 체계
에러 핸들링 및 Fallback 전략
Q7. Next.js 같은 프레임워크 대신 직접 구현한 SSR/SSG의 장단점은 무엇인가요?
1.깊은 이해와 학습 효과
SSR의 내부 동작 원리를 정확히 이해할 수 있었습니다. renderToString이 어떻게 동작하는지, hydration 과정에서 무슨 일이 일어나는지 직접 경험할 수 있었습니다.
2.완전한 커스터마이징 자유도
라우팅 로직, 캐싱 전략, 빌드 과정을 모두 직접 구현할 수 있어서 프로젝트 특성에 맞게 최적화할 수 있습니다.
3.번들 크기
필요한 기능만 구현하므로 Next.js보다 작은 번들 크기를 유지할 수 있습니다.
Q8. Next.js 를 이용하여 SSG 방식으로 배포하려면 어떻게 해야 좋을까요?
App Router 활용
Next.js의 App Router를 사용해서 폴더 기반 라우팅으로 변경하고, generateStaticParams와 generateMetadata를 활용해서 동적 상품 페이지들을 빌드 시점에 생성할 수 있습니다.
Incremental Static Regeneration (ISR)
모든 상품 페이지를 빌드 시점에 생성하는 것보다는, 인기 상품들만 미리 생성하고 나머지는 ISR로 처리하는 것이 효율적일 것 같습니다.
코드 품질 향상
자랑하고 싶은 구현
개선하고 싶은 부분
성능 최적화
무한스크롤에서 메모리 누수를 방지하기 위한 가상화나 아이템 수 제한 로직을 추가하고 싶습니다. 또한 이미지 지연 로딩과 placeholder를 구현해서 초기 로딩 속도를 개선하고 싶습니다.
테스트 코드
현재 테스트 코드가 부족한 상태입니다. 특히 SSR 렌더링 로직이나 상태 관리 부분에 대한 단위 테스트와 통합 테스트를 추가해야 합니다.
리팩토링 계획
현재 productUseCase.ts에서 비즈니스 로직과 API 호출이 섞여있는데, 이를 분리하고 싶습니다.
ProductDetail 컴포넌트가 너무 크므로, 브레드크럼, 이미지 뷰어, 수량 선택기 등으로 분해해서 재사용성을 높이고 싶습니다.
학습 연계
다음 학습 목표
Serverless 환경에서의 SSR 최적화
현재 Express 서버 기반 구현을 Cloudflare Workers나 Vercel Edge Functions로 마이그레이션하면서 Cold Start 최적화와 메모리 제약 대응 방안을 학습하고 싶습니다. 특히 현재 구현의 vite.ssrLoadModule 같은 동적 모듈 로딩을 Edge Runtime에서 어떻게 최적화할 수 있는지 궁금합니다.
GraphQL과 SSR/SSG 연동 방안
현재 REST API 기반의 데이터 페칭을 GraphQL로 전환하여 N+1 쿼리 문제를 해결하고, DataLoader 패턴을 활용한 효율적인 데이터 로딩을 구현해보고 싶습니다.
React 18의 Concurrent Features 활용
현재 renderToString을 사용한 동기적 렌더링을 Streaming SSR과 Suspense를 활용한 점진적 렌더링으로 개선하여 사용자 경험을 향상시키는 방법을 학습하고 싶습니다.
실무 적용 계획
랜딩 페이지 SSG 적용
이벤트 랜딩 페이지들을 SSG로 구현해서 SEO 점수를 개선하고, CDN 캐싱을 통해 로딩 속도를 향상시키고 싶습니다.
상태 관리 개선
현재 Redux Toolkit를 사용하고 있는데, 이번에 구현한 것처럼 더 간단한 커스텀 스토어로 리팩토링을 검토해보고 싶습니다. 특히 보일러플레이트 코드가 많은 부분들을 개선할 수 있을 것 같습니다.
리뷰 받고 싶은 내용
이번 과제는 SSR과 SSG를 직접 구현해보는 것이었는데, 확실히 쉽지 않았습니다.
특히 SSR의 전체적인 동작 과정과 SSG의 차이를 실제 코드로 구현해보는 과정에서 많이 헤맸습니다.
그래서 리뷰받고 싶은 내용을 구체적으로 정리하기는 어려웠던거 같습니다 ㅠㅠ