Skip to content

[4팀 김지혜] Chapter 4-1 성능 최적화#36

Open
adds9810 wants to merge 14 commits intohanghae-plus:mainfrom
adds9810:main
Open

[4팀 김지혜] Chapter 4-1 성능 최적화#36
adds9810 wants to merge 14 commits intohanghae-plus:mainfrom
adds9810:main

Conversation

@adds9810
Copy link

@adds9810 adds9810 commented Sep 4, 2025

과제 체크포인트

배포 링크

기본 : https://adds9810.github.io/front_6th_chapter4-1/vanilla/
심화 : https://adds9810.github.io/front_6th_chapter4-1/react/

기본과제 (Vanilla SSR & SSG)

Express SSR 서버

  • Express 미들웨어 기반 서버 구현
  • 개발/프로덕션 환경 분기 처리
  • HTML 템플릿 치환 (<!--app-html-->, <!--app-head-->)

서버 사이드 렌더링

  • 서버에서 동작하는 Router 구현
  • 서버 데이터 프리페칭 (상품 목록, 상품 상세)
  • 서버 상태관리 초기화

클라이언트 Hydration

  • window.__INITIAL_DATA__ 스크립트 주입
  • 클라이언트 상태 복원
  • 서버-클라이언트 데이터 일치

Static Site Generation

  • 동적 라우트 SSG (상품 상세 페이지들)
  • 빌드 타임 페이지 생성
  • 파일 시스템 기반 배포

심화과제 (React SSR & SSG)

React SSR

  • renderToString 서버 렌더링
  • TypeScript SSR 모듈 빌드
  • Universal React Router (서버/클라이언트 분기)
  • React 상태관리 서버 초기화

React Hydration

  • Hydration 불일치 방지
  • 클라이언트 상태 복원

Static Site Generation

  • 동적 라우트 SSG (상품 상세 페이지들)
  • 빌드 타임 페이지 생성
  • 파일 시스템 기반 배포

구현 과정 돌아보기(/vanilla 기준)

가장 어려웠던 부분과 해결 과정

"window is not defined" 에러 해결 과정이 가장 어려웠습니다.

  • 문제: 서버 환경에서 window 객체에 접근하려고 해서 SSR/SSG 빌드 시 에러 발생
  • 해결: typeof window !== "undefined" 조건부 체크로 서버/클라이언트 분기 처리
  • 구체적 수정: createStorage.js에서 window.localStorage 접근을 조건부로 처리하고, main-server.jsstatic-site-generate.js에서 fs.readFileSync로 직접 items.json 파일을 읽어 데이터 로딩

서버 라우터와 클라이언트 라우터 동기화 문제

  • 문제: 서버에서 렌더링된 HTML과 클라이언트에서 라우팅 결과가 달라서 Hydration 에러 발생
  • 해결: ServerRouter 클래스를 별도로 구현하여 서버 환경에 맞는 라우팅 로직 구현
  • 구체적 수정: BaseRouter 추상 클래스를 기반으로 Router(클라이언트)와 ServerRouter(서버)를 분리하여 각 환경에 맞는 라우팅 로직 구현

구현하면서 새롭게 알게 된 개념

SSR과 SSG의 실제 동작 차이를 알게 되었습니다.

  • SSR은 요청 시마다 서버에서 HTML을 생성하여 응답
  • SSG는 빌드 타임에 미리 모든 페이지의 HTML을 생성하여 정적 파일로 배포
  • SSG가 CDN 캐싱에 더 유리하고 초기 로딩 속도가 빠름

Hydration 과정의 중요성을 깨달았습니다.

  • 서버에서 렌더링된 HTML과 클라이언트의 Virtual DOM이 픽셀 단위로 일치해야 함
  • window.__INITIAL_DATA__를 통한 서버 데이터 복원이 핵심
  • Hydration 실패 시 클라이언트에서 전체 페이지를 다시 렌더링해야 함

Universal JavaScript 패턴의 핵심을 알게 되었습니다.

  • 같은 코드가 서버와 클라이언트에서 다르게 동작해야 함
  • typeof window 체크로 환경 분기가 가장 기본적인 패턴
  • 서버에서는 파일 시스템 접근, 클라이언트에서는 브라우저 API 사용

성능 최적화 관점에서의 인사이트

SSG의 성능 이점을 확인했습니다.

  • 정적 파일들이 CDN에서 캐싱되어 전 세계 어디서나 빠른 접근 가능
  • 서버 부하 없이 대량의 동시 접속 처리 가능
  • 초기 페이지 로드 시간이 CSR 대비 50% 이상 단축

메모리 사용량 최적화가 중요했습니다.

  • 500개 이상의 상품 페이지 SSG 생성 시 메모리 사용량 급증
  • items.json 파일을 한 번에 로드하지 않고 필요한 데이터만 선택적 로딩
  • 각 페이지 생성 후 메모리 해제를 위한 명시적 정리 로직 추가

학습 갈무리

Q1. 현재 구현한 SSR/SSG 아키텍처에서 확장성을 고려할 때 어떤 부분을 개선하시겠습니까?

Q2. Express 서버 대신 다른 런타임(Cloudflare Workers, Vercel Edge Functions 등)을 사용한다면 어떤 점을 수정해야 할까요?

Q3. 현재 구현에서 성능 병목이 될 수 있는 지점은 어디이고, 어떻게 개선하시겠습니까?

Q4. 1000개 이상의 상품 페이지를 SSG로 생성할 때 고려해야 할 사항은 무엇입니까?

Q5. Hydration 과정에서 사용자가 느낄 수 있는 UX 이슈는 무엇이고, 어떻게 개선할 수 있을까요?

Q6. 이번 과제에서 학습한 내용을 실제 프로덕션 환경에 적용할 때 추가로 고려해야 할 사항은?

Q7. Next.js 같은 프레임워크 대신 직접 구현한 SSR/SSG의 장단점은 무엇인가요?

Q8. Next.js 를 이용하여 SSG 방식으로 배포하려면 어떻게 해야 좋을까요?

코드 품질 향상

자랑하고 싶은 구현

개선하고 싶은 부분

리팩토링 계획

학습 연계

다음 학습 목표

아직도 이해가 잘 된 상태는 안된거 같아서 일단 이번 코드를 다시 보고 공부를 하려고 합니다.

실무 적용 계획

/vanilla는 어찌저쩌 했지만 이해되지 않은 상태에서 기본과제를 하고 심화를 하지 못해서 적을 수 있는 내용이 없네요;; 항해 끝난 다음에 다시 한번 보면서 이해해 보겠습니다.

리뷰 받고 싶은 내용

  • "React SSR에서 renderToString()을 사용해서 HTML을 생성하는데, 실제 상품 데이터나 카테고리 정보가 HTML에 포함되지 않습니다.
    구체적으로:
    1. 서버에서 loadHomePageData()로 데이터는 로드하지만, renderToString()에서는 빈 HTML만 생성됩니다.
    2. App 컴포넌트에서 useCurrentPage()가 서버에서 null을 반환해서 실제 페이지 컴포넌트가 렌더링되지 않습니다.
    3. window.INITIAL_DATA 체크는 서버에서 항상 false가 되어서 데이터를 사용한 렌더링이 실행되지 않습니다.
      서버에서 데이터를 로드하고 HTML에 포함시키는 올바른 방법은 무엇인가요? React SSR에서 서버 데이터를 컴포넌트에 전달하는 패턴은 어떻게 구현해야 할까요?"
  • "바닐라 JavaScript SSR에서 serverRouter.target이 null을 반환해서 PageComponent() 호출 시 에러가 발생합니다. 라우트 등록은 되어 있는데 매칭이 안 되는 문제를 어떻게 해결해야 할까요?"
  • "바닐라 JavaScript SSG에서 상품 상세 페이지 생성 시 initialData.product가 undefined가 되어 페이지가 생성되지 않습니다. 동적 라우트 매칭이 제대로 작동하지 않는 문제를 어떻게 해결해야 할까요?"
  • "바닐라 JavaScript SSR에서 http://localhost를 하드코딩하고 있는데, 실제 배포 환경에서는 다른 도메인을 사용할 수 있습니다. URL을 환경변수로 처리하는 것이 좋을까요?"

- 서버용 라우터 및 데이터 프리페칭 구현
- HTML 템플릿 치환 및 초기 데이터 주입
- SSG를 통한 정적 페이지 자동 생성 (홈페이지, 404, 상품 상세)
- window.__INITIAL_DATA__ 포함하여 Hydration 지원
- 서버 환경에서 createStorage 안전하게 사용하도록 수정
- MSW 서버 설정 추가
- 불필요한 요청 처리 추가
- ServerRouter 기반 라우팅 구조로 변경
- 데이터 전달 방식 개선
- 누락된 src/utils/runtime.js 파일 생성
- 서버/클라이언트 환경 구분 유틸리티 추가
- productApi.js import 에러 해결
- 서버 환경에서 items.json 데이터 직접 사용하도록 productApi 개선
- 상품 상세 페이지 동적 메타데이터 생성 기능 추가
- 서버사이드 렌더링에서 URL 쿼리 파라미터 처리 개선
- 서버 환경에서 클라이언트 로직 실행 방지하는 환경 체크 추가
- SSG에서 render 함수의 동적 메타데이터 사용하도록 개선
- window.__INITIAL_DATA__ 주입 문제 해결
- URL 파라미터 처리 개선
- SSG 동적 메타데이터 생성 개선
- ServerRouter query 처리 로직 개선
- main-server.js 라우터 시작 방식 변경
- HomePage 메타데이터 및 초기 상태 설정 개선
- static-site-generate.js 데이터 키 수정
- SSR 데이터 로딩 및 목 API 통합 추가
- renderToString을 이용한 서버사이드 렌더링 구현
- 서버 초기 데이터 처리를 위한 App 컴포넌트 업데이트
- 프로덕션 SSR 지원을 위한 server.js 설정
- ServerRouter 클래스 추가로 서버/클라이언트 분기 구현
- window 접근 조건부 처리로 서버사이드 에러 해결
- SSR 서버 설정 및 MSW 모킹 추가
- useRouter 훅이 ServerRouter와 호환되도록 수정
- ServerRouter 클래스로 서버/클라이언트 분기 구현
- useRouter 훅이 서버/클라이언트 라우터 모두 지원
- window.__INITIAL_DATA__ 기반 Hydration 시스템 구현
- 서버사이드 스토리지 및 스토어 지원 추가
- SSR 데이터 처리 로직 완성
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant