원티드 프리온보딩 챌린지 7월 과제로 CSR과 SSR의 이해란 주제로 포스팅을 하게되었다!
1. CSR이란? 이것의 장단점은 무엇인가요?
CSR이란 Client-side Rendering 의 줄임말이다.
말 그대로 '클라이언트 쪽에서 렌더링을 한다' 라는 말인데,
여기서 클라이언트는 브라우저이기 때문에 브라우저가 렌더링을 처리하는 방식이다.
서버에서 HTML을 받아와서 JS주소를 서버로 요청해 동적으로 사용자에게 최종적인 어플리케이션을 보여준다.
위 그림은 CSR 의 순서이다.
- 유저는 웹사이트에 요청을 보낸다.
- Edge Caching 은 HTML 파일과 JS에 접근할 수 있는 링크를 빠르게 보낸다
- 브라우저는 HTML, JS를 다운로드 받는다.
- 브라우저는 JS를 다운로드 받는다.
- 모두 다운로드가 되면 JS가 실행되고, 데이터를 불러오기 위한 API가 호출된다. 유저는 placeholder를 바라본다.
- 서버는 API로부터 온 요청을 받아 응답한다.
- 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로 구현했을 때에는 해결이 가능함.
- JS 코드가 동작하기 전에 완성된 형태의 템플릿을 서버로부터 전달받아 검색로봇이 페이지를 크롤링하기에 적합한 상태가 됨(SEO)
- 초기 페이지를 로딩 시에 필요한 콘텐츠를 서버에서 렌더링하여 전달하기 때문에 사용자는 빠르게 페이지를 볼 수 있음.
결론적으로, 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 는 다음과 같다.
여기서 보면 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
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://yeoossi.tistory.com/40