NextJS의 가장 큰 특징으로 "Server-side Rendering(SSR)을 지원"한다는 것입니다.
일반적인 React App은 CSR(Client-side Rendering)로 동작합니다. CSR은 초기 렌더링되는 시간이 SSR보다 오래걸립니다.
그 이유는 하나의 빈 HTML 파일(SPA)을 응답받아 script 태그로 번들 파일인 하나의 큰 자바스크립트 파일을 로드하여 실행하고 렌더링(CSR)하기 때문입니다.
이는 초기에 자바스크립트의 코드를 로드하고 파싱하는 동안 사용자는 빈 화면을 보게될 것입니다.
또한 웹 크롤러 봇은 자바스크립트를 실행하지 못하고 HTML 파일의 정보만 수집하기 때문에 CSR인 React App이 전달받는 빈 HTML 문서로 인해서 빈 페이지로 인식하게 됩니다. 즉,검색 엔진 최적화(SEO)에 취약하다는 단점을 갖고 있습니다.
참고로 웹 크롤러란 방대한 웹 페이지를 방문하여 각종 정보를 자동적으로 수집하는 프로그램으로 검색 엔진의 근간이 됩니다.
이러한 문제를 해결하기 위해서 서버 사이드 렌더링이 필요합니다. SSR은 서버에서 콘텐츠가 포함된 HTML 파일을 미리 만들어 브라우저에게 전달하기 때문에 브라우저는 이를 즉시 화면에 렌더링합니다. 즉, 자바스크립트 코드가 로드되어 실행될 때까지 기다리지 않아도 됩니다.
이는 웹 크롤러가 페이지에 대한 정보도 수집이 가능하게 될 것입니다. 서버가 전달해준 HTML 문서가 빈 HTML 문서가 아닌 콘텐츠가 포함된 HTML 문서이기 때문입니다.
이렇게 서버측에서 콘텐츠가 포함된 HTML 문서를 미리 만드는 동작을 "pre-rendering"이라고 합니다.
서버측에서 전달한 HTML 문서 뿐만 아니라 자바스크립트 파일도 클라이언트측에게 전달해줍니다. 하나의 HTML 문서(SPA)를 전달받아 즉시 렌더링한 이후에는 자바스크립트 파일을 실행하여 화면을 동적으로 업데이트(CSR)합니다.
NextJS는 아래와 같은 방식으로 동작합니다.
클라이언트측에서 페이지에 대한 리소스를 요청하면 서버측에서 요청한 페이지를 pre-rendering하여 콘텐츠가 포함된 HTML 문서를 응답하고 클라이언트는 이를 즉시 렌더링합니다.
pre-rendering된 HTML 문서를 렌더링한 뒤에는 클라이언트측에서 자바스크립트 코드를 통해 화면을 동적으로 업데이트
이처럼 Next App은 기존 React App처럼 하나의 HTML 문서만 사용하며 이후 자바스크립트를 통해 화면을 동적으로 업데이트합니다.
React App과 차이점은 전달받는 HTML 문서가 빈 HTML 문서가 아닌 서버측에서 미리 콘텐츠가 포함된 HTML 문서를 전달해주는다는 차이점이 존재합니다.
이는 초기 애플리케이션 접속시 사용자가 빈 화면을 보지않게되며, 웹 크롤러 봇이 HTML 문서를 읽어 페이지에 대한 정보 수집도 가능하게 됩니다.
// pages/index.js
const HomePage = () => {
return <h1>Home Page!!</h1>;
}
export default HomePage;
next 프로젝트의 pages 폴더의 index.js 파일의 내용이 다음과 같은 경우 URL 경로로 "/" 요청시 전달받는 HTML 문서는 아래와 같습니다.
HTML 문서에 <h1>Home Page!!</h1>
가 포함된 HTML 문서가 렌더링된 것을 확인할 수 있습니다.
이처럼 기존 React App은 빈 div 요소 하나만 존재했다면 Next App은 페이지의 콘텐츠가 포함된 HTML 문서를 응답으로 전달해줍니다.
클라이언트측에서 HTML 문서를 요청하면 서버측에서는 pre-rendering을 통해 생성된 HTML 문서를 클라이언트측에 전달하고 자바스크립트 파일도 클라이언트측에 전달합니다.
클라이언트측에서는 전달받은 HTML 문서를 즉시 렌더링 한 뒤 렌더링된 HTML 문서 위에 해당 페이지 컴포넌트 함수를 실행하여 리렌더링 과정을 거치게 됩니다.
"Hydrate"란 클라이언트측에서 화면에 렌더링된 UI와 JS 코드를 서로 매칭시키는 과정을 말합니다.
즉, Hydrate는 서버측에서 pre-rendering된 HTML 문서를 요청받아 렌더링한 뒤에 클라이언트측에서 발생합니다.
클라이언트가 서버로부터 전달받은 HTML 문서는 단순히 화면에 시각적으로 렌더링을 위한 HTML 문서이며 자바스크립트 코드가 없습니다.
서버에서 pre-rendering된 HTML 문서를 클라이언트에게 전달하고 나서 추가적으로 번들링된 자바스크립트 파일도 클라이언트에게 전송합니다.
Hydrate 과정을 포함한 렌더링 과정은 아래와 같습니다.
서버측에서 pre-rendering한 HTML 문서를 응답으로 전달해주면 브라우저가 이를 화면에 즉각적으로 렌더링합니다.
이후 Hydrate로 인해 해당 페이지 컴포넌트 함수를 클라이언트측에서 실행하여 화면을 리렌더링하게 됩니다.
Hydrate 과정 이후에는 오직 자바스크립트 코드를 통해서만 화면을 동적으로 업데이트 합니다.
다시 한 번 말하자면 Hydrate 과정은 서버측에게 HTML 문서를 요청하여 pre-rendering된 HTML 문서를 렌더링한 뒤에 발생하는 과정입니다.
Next App 또한 SPA로서 동작하기 때문에 초기 HTML 문서를 렌더링한 이후에는 Hydrate 과정이 일어나지 않습니다.
NextJS의 또 다른 특징은 바로 "파일 기반 라우팅"입니다. react 라이브러리에는 Routing 기능이 존재하지 않으며 Routing을 사용하기 위해서는 "react-router-dom" 패키지를 추가적으로 설치해야 했습니다.
Routing이란 URL의 경로가 변경되면 그에 맞는 UI를 화면에 렌더링해주는 것입니다. 단, SPA로서 동작해야하기 때문에 새로운 요청을 보내지 않고 URL의 path가 변경되는 것을 인지하여 그에 맞는 컴포넌트를 조건부 렌더링하도록 구현해야 합니다.
즉, 실제로는 하나의 페이지를 사용하고 있으며 URL 경로에 따라 렌더링될 컴포넌트를 결정하는 것입니다.
NextJS는 프로젝트의 "pages"라는 폴더를 통해 자동적으로 Routing 처리를 해줍니다. 이는 Routing을 위한 추가적인 패키지나 코드가 필요하지 않습니다.
참고로 NextJS는 기본적으로 각 페이지 컴포넌트마다 "코드 스플리팅"이 되어있으며, 해당되는 페이지에 연관된 정보들만 로드하게 됩니다.
만약 해당 페이지 내 다른 페이지로 이동하는 링크가 존재하는 경우 연 결된 페이지의 정보들도 미리 로드합니다.
이후 현재 페이지에서 다른 페이지로 이동하는 링크를 클릭하면 미리 로드한 정보를 이용하여 연결된 페이지로 리렌더링합니다.
앞서 설명한 SSR과 pre-rendering을 위해 NextJS는 스크립트를 실행할 수 있는 서버를 갖고 있어야 합니다. 이러한 서버를 갖고 있기 때문에 서버에서 동작할 코드도 포함할 수 있는 Fullstack 프로젝트를 구현할 수 있습니다.
작성한 서버 코드는 클라이언트측에서 전달되지 않기 때문에 확인 또한 불가능하며, 단지 NextJS 서버에서 실행될 코드만을 작성할 수 있습니다.