Develop

CSR과 SSR의 이해

dawonny 2023. 7. 8. 03:27
728x90
반응형

원티드 프리온보딩 챌린지 7월 과제로 CSR과 SSR의 이해란 주제로 포스팅을 하게되었다!

 


1. CSR이란? 이것의 장단점은 무엇인가요?

CSR이란 Client-side Rendering 의 줄임말이다.

말 그대로 '클라이언트 쪽에서 렌더링을 한다' 라는 말인데,

여기서 클라이언트는 브라우저이기 때문에 브라우저가 렌더링을 처리하는 방식이다.

 

서버에서 HTML을 받아와서 JS주소를 서버로 요청해 동적으로 사용자에게 최종적인 어플리케이션을 보여준다.

위 그림은 CSR 의 순서이다.

  1. 유저는 웹사이트에 요청을 보낸다.
  2. Edge Caching 은 HTML 파일과 JS에 접근할 수 있는 링크를 빠르게 보낸다
  3. 브라우저는 HTML, JS를 다운로드 받는다.
  4. 브라우저는 JS를 다운로드 받는다.
  5. 모두 다운로드가 되면 JS가 실행되고, 데이터를 불러오기 위한 API가 호출된다. 유저는 placeholder를 바라본다.
  6. 서버는 API로부터 온 요청을 받아 응답한다.
  7. API로부터 받은 데이터를 placeholder에 채우고, 페이지를 상호작용할 수 있게 된다.

 

 

CSR의 장점

  • 화면 깜빡임이 없다.
    • 덕분에 빠른 페이지 전환
    • 새로고침 없이도 콘텐츠 업데이트가 가능하여 좋은 사용자 경험
  • 초기 로딩 이후 구동 속도가 빠르다.
  • 서버 부하가 분산된다.
    • 서버에서 정적인 콘텐츠를 한번만 제공하고 이후에는 필요한 데이터만 요청하기 때문에 서버의 부하를 줄일 수 있다.

CSR의 단점

  • 초기 로딩 속도가 느리다
    • 서버에 첫 요청 시 전체 페이지에 대한 모든 문서 파일을 받다 보니 SSR보다 로딩 속도가 느리다.
    • 초기 로딩 완료 전까지는 빈페이지나 로딩 화면이 보일 수 있다.
  • SEO(검색엔진 최적화)에 불리하다.
    • 포털 사이트 검색엔진 크롤러가 웹사이트에 대한 데이터를 제대로 수집하지 못하는 경우가 발생할 수 있다.
      구글의 검색엔진의 경우 JS 엔진이 내장되어 있어 크롤링이 되지만 네이버, 다음의 경우 검색엔진이 제대로 크롤링 하지 못하기 때문에 별도의 보완작업이 필요하다.

 

2. SPA로 구성된 웹앱에서 SSR이 필요한 이유는 무엇인가요?

SPA 란?

SPA는 사용자가 페이지를 로드할 때 전체 페이지를 다시 로드하는 대신에 

초기 로딩 시에 모든 필요한 리소스(HTML, CSS, JS)를 한번에 다운로드 받고,

이후에는 필요한 데이터만 동적으로 로드해서 페이지를 업데이트하는 방식으로 작동한다.

 

SSR 이란?

Server-side rendering의 줄임말. 

웹 애플리케이션을 서버에서 렌더링하는 방식.

 

일반적인 SPA 에서는 클라이언트 측에서 JS를 사용해서 페이지를 렌더링하고, 데이터를 동적으로 가져와서 업데이트함.

 

하지만 SSR에서는 서버측에서 초기 페이지 로드시에 필요한 HTML, CSS 및 데이터를 생성하여 클라이언트에게 전달함.

이렇게 서버에서 생성된 완전한 HTML 페이지가 브라우저에 의해 직접 렌더링되어 사용자에게 보여짐.

 

따라서 SPA를 CSR 방식으로 구현했을 때 단점이었던 초기 로딩 속도가 검색 엔진 최적화 문제 등을 SSR로 구현했을 때에는 해결이 가능함.

  1. JS 코드가 동작하기 전에 완성된 형태의 템플릿을 서버로부터 전달받아 검색로봇이 페이지를 크롤링하기에 적합한 상태가 됨(SEO)
  2. 초기 페이지를 로딩 시에 필요한 콘텐츠를 서버에서 렌더링하여 전달하기 때문에 사용자는 빠르게 페이지를 볼 수 있음.

결론적으로, CSR 의 문제를 SSR로 해결할 수 있게 된 것!

 

3. Next.js 프로젝트에서 yarn start(or npm run start) 스크립트를 실행했을 때 실행되는 코드를 Next.js Github 레포지토리에서 찾은 뒤, 해당 파일에 대한 간단한 설명을 첨부해주세요.

next.js 를 해본적이 없지만... 일단 next 프로젝트부터 설치해보기로 했다.

npx create-next-app preonboarding-fe-7

그리고 npm run start 명령어를 입력했더니 아래와 같이 출력됐다.

 

next start 라는 명령어가 실행되는 것 같다.

 

next start 라는 명령어는 pacakage.json 의 scripts 에서 확인할 수 있다.

이 next start 에 대한 내용은 node_modules/next/dist/cli/next-start.js 에서 찾아볼 수 있다.

 

next-start.js 는 다음과 같다.

node_modules/next/dist/cli/next-start.js

여기서 보면 nextStart가 async await 비동기 처리가 되어있는데

await 이 어디있나 찾아봤는데 startServer 라는 것이 실행되는 곳에 있었다.

startServer 에 대한 정보를 찾아봤다.

node_modules/next/dist/server/lib/start-server.js 라는 경로에 있었다.

vercel/next.js 깃허브 기준으로는 아래 경로에 있다.
https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/start-server.ts

node_modules/next/dist/server/lib/start-server.js

ChatGPT에게 설명을 참고하여 작성했다.

 


1. `startServer` 함수는 Next.js 서버를 시작하는 역할을 합니다.
2. 함수는 `dir`, `port`, `isDev`, `workerThreads`, `isNextDevCommand`와 같은 매개변수를 받습니다.
3. 함수는 `createServer` 함수를 사용하여 HTTP 서버를 생성합니다.
4. `dir`은 Next.js 프로젝트의 디렉토리 경로입니다.
5. `port`는 서버가 실행될 포트 번호입니다.
6. `isDev`는 개발 모드인지 여부를 나타냅니다.
7. `workerThreads`는 워커 스레드를 사용할지 여부를 결정합니다.
8. `isNextDevCommand`는 Next.js 개발 명령어를 실행 중인지 여부를 나타냅니다.
9. 서버의 `request` 이벤트를 처리하는 함수를 정의하고, 이벤트 핸들러 내에서 Next.js 앱의 요청 핸들러를 호출합니다.
10. `keepAliveTimeout` 값이 설정되면, 서버의 `keepAliveTimeout` 속성에 해당 값을 할당합니다.
11. 서버를 시작하고 서버의 주소와 포트를 로그에 출력합니다.
12. 서버 시작 중에 오류가 발생하면 오류를 처리하고 프로세스를 종료합니다.
13. 서버가 시작되면 종료 함수를 반환합니다. 이 함수는 서버를 닫고 사용 중인 소켓들을 해제하는 역할을 합니다.

 

createServer 라는 함수를 이용해서 HTTP 서버를 생성하고 종료까지의 과정을 담고 있는 것 같았다.


1. `startServer` 함수는 `dir`, `prevDir`, `port`, `isDev`, `hostname`, `useWorkers`, `allowRetry`, `keepAliveTimeout`, `onStdout`, `onStderr`와 같은 매개변수를 받습니다.
2. 함수 내부에서는 서버의 소켓 연결, 워커 관리, 핸들러 설정 등 다양한 기능을 수행합니다.
3. 함수가 실행되면 먼저 필요한 변수와 상태를 초기화합니다. 예를 들어, `sockets`라는 셋을 생성하여 연결된 소켓들을 추적합니다.
4. 다음으로, 요청과 업그레이드를 처리하기 위한 핸들러 함수를 설정합니다. 이 핸들러 함수들은 초기화 전에는 에러를 던지고, 초기화 후에는 실제 요청을 처리합니다.
5. `http.createServer`를 사용하여 서버를 생성하고, 요청과 업그레이드 이벤트를 처리합니다.
6. 서버의 `error` 이벤트를 처리하여 오류가 발생하면 적절하게 대응합니다.
7. 서버가 시작되면 주소와 포트 정보를 로그에 출력합니다.
8. `useWorkers` 매개변수에 따라 워커 스레드를 사용할지 여부를 결정합니다.
   - `useWorkers`가 `true`로 설정되면 워커 스레드를 사용하는 로직을 실행합니다. 워커 스레드를 사용하여 라우터 워커를 시작하고, 프록시 서버를 설정하여 요청을 라우터 워커로 전달합니다.
   - `useWorkers`가 `false`이면 메인 프로세스에서 Next.js 애플리케이션을 시작합니다. 앱의 요청 핸들러와 업그레이드 핸들러를 설정하고 앱을 실행합니다.
9. 서버 시작 중에 오류가 발생하면 오류를 처리하고 프로세스를 종료합니다.
10. 서버가 시작되면 `teardown` 함수를 반환합니다. 이 함수는 서버를 닫고 연결된 소켓들을 해제하는 역할을 합니다.

`startServer` 함수는 Next.js 프로젝트의 서버 시작에 필요한 다양한 로직과 기능을 담고 있습니다. 이를 통해 서버의 초기화, 핸들러 설정, 워커 관리 등을 수행하여 Next.js 애플리케이션을 실행하고 관리할 수 있습니다.

 

코드가 길고 낯설어서 모두 이해한 것은 아니지만 별 생각없이 사용했던 명령어 하나로 

이런 저런 파일들을 뜯어보며 이해해보려고 노력하니까 명령어 하나에도 상세한 로직이 모두 설정되어있다는 것을 알게 되었다.


아래 포스팅을 참고하여 작성하였습니다.

ref:

https://www.startupcode.kr/company/blog/archives/12

https://velog.io/@kwak1539/%EC%9B%90%ED%8B%B0%EB%93%9C-%ED%94%84%EB%A6%AC%EC%98%A8%EB%B3%B4%EB%94%A9-%EC%B1%8C%EB%A6%B0%EC%A7%80-7%EC%9B%94-%EC%82%AC%EC%A0%84%EA%B3%BC%EC%A0%9C-u9doejs6

https://yeoossi.tistory.com/40

https://velog.io/@carloskim/%EC%9B%90%ED%8B%B0%EB%93%9C-%ED%94%84%EB%A6%AC%EC%98%A8%EB%B3%B4%EB%94%A9-%EA%B3%BC%EC%A0%9CCSR%EA%B3%BC-SSR%EC%9D%98-%EC%9D%B4%ED%95%B4

 

728x90
반응형