CSR 과 SSR with Next.js

하머·2022년 10월 4일
0

1. CSR(Client-side Rendering)이란

  • 유저가 컨텐츠 요청을 했을 때, 우선 빈 뼈대의 HTMl을 보낸 뒤 연결된 JS 링크로 DOM을 그리는 것
  • 장점
    • 서버 부담 감소
    • 사용자 입장에서 깜빡임 없이 페이지 전환
  • 단점
    • SEO에서 불리함(웹 크롤링을 해오는 검색엔진은 빈 뼈대만 가져오게 되므로)
    • 초기 렌더링 시간 증가

2. SSR(Server-side Rendering)이란

  • 유저가 컨텐츠 요청을 했을 때, 서버에서 렌더링 준비를 마친 HTML을 전송하고 그 뒤 JS 코드를 전송하는데 초기 HTML 렌더링 덕분에 검색엔진이 컨텐츠의 내용을 읽을 수 있습니다.
  • 장점
    • 초기 렌더링 속도가 비교적 적다
    • SEO에 유리하다
  • 단점
    • 서버 부담 증가
    • TTI 증가(렌더링 최적화 점수증가)
    • 화면 깜빡임으로 인한 사용자 경험 불리함

3. Next.js와 Pre-Rendering

Next.js의 작동원리를 찾고 Next.js의 Pre-Rendering 방법들을 나열 해 보았습니다.

  • nextjs.org - How Next.js Works

    1. Rust로 작성된 컴파일러 와 SWC(Speedy Web Compiler)플랫폼을 사용해 빠른속도로 코드들을 컴파일, 경량화(Minify), 번들링 합니다.
    2. 번들링 과정에서 동적 라우팅, 첫 페이지 로딩 성능 향상을 위해 Code Splitting이 이루어집니다.
    3. 빌드가 완료되면 Next.js는 개발자의 코드를 아래의 효율적인 파일들로 바꾸어 주고 런타임으로 넘어갑니다.
      • 페이지 정적 생성을 위한 HTML 파일들
      • 서버에서 페이지를 렌더링 하기위한 자바스크립트 파일
      • 클라이언트에서 상호작용 페이지를 만드는 자바스크립트 파일 (Hydration)
      • CSS 파일
    4. 런타임에서 사용자가 요청 하면 Next.js 는 서버에서 미리 생성된 HTML을 바탕으로 초기 UI를 렌더링 한뒤 Hydration으로 동적 UI를 렌더링 하는 방법인 Pre-Rendering 으로 클라이언트 화면을 렌더링 해줍니다.
    5. Next.js 는 Pre-Rendering의 두가지 방법(SSR, SSG) 모두 제공합니다.
      • SSR(Server-Side Rendering): 각 요청마다 서버는 해당하는 페이지의 HTML 서버에서 미리 생성한 뒤, 생성된 HTML과 JSON, 페이지가 상호작용 하도록 하는 자바스크립트 코드를 보내줍니다. 이후, HTML파일이 초기 렌더링되는 동안 리액트는 JSON과 자바스크립트를 사용해 상호작용 가능한 컴포넌트들로 만드는데 이 과정을 Hydration 이라고 한다.
      • SSG(Static Site Generation): SSR과 다르게 런타임에서 보내주는 서버가 생성되지 않고, 웹앱이 배포될 때, 빌드타임에서 생성된 정적 컨텐츠를 저장하고 각각의 요청마다 재사용해 보내주거나 CDN서비스에 저장해 보내주는 방식으로 사용된다.
      • ISR(Incremental Static Regeneration): SSG에서는 컨텐츠가 수정되면 배포 과정에서 전체 사이트를 다시 빌드해야 했지만, ISR을 사용하면 전체 사이트를 다시 빌드하지 않고 수정된 페이지만 다시 정적 생성된다. 일정 주기로 정적 페이지를 재생성하고 사용자에게 수정된 정적 페이지를 보여주는 방식으로 이루어진다.
  • 해당 파일

    packages/next/server/next.ts
    
    // React JSX를 HTML파일로 렌더링
    async renderToHTML(...args: Parameters<Server['renderToHTML']>) {
      const server = await this.getServer()
      return server.renderToHTML(...args)
    }
    
    [...]
    
    // Pre-Rendering 을 위해 초기 정적페이지 전달
    async serveStatic(...args: Parameters<Server['serveStatic']>) {
      const server = await this.getServer()
      return server.serveStatic(...args)
    }
    
    packages/next/client/index.tsx
    
    // Hydrate 분기
    if (shouldHydrate) {
      ReactDOM.hydrate(reactEl, domEl)
      shouldHydrate = false
    } else {
      ReactDOM.render(reactEl, domEl)
    }
    

0개의 댓글