React&Next.js

[Next.js] Next.js 구조를 (약간) 파헤쳐 보았다. - (1)

jjin502 2024. 6. 13. 18:32

개요

Vercel에서 만든 React 프레임워크 Next.js는 가면 갈수록 많이 사용되고 있다.

지난 몇 년간 꾸준히 발전하며,이 추이가 계속되면 하루 아침에 Next.js가 앞서있을 것 같다고 생각도 했다.

필자 또한 프론트엔드 개발자로서 기본적인 이해도를 높이고,

제대로 사용해보고 싶어서 Next.js를 나만의 방식으로 파헤쳐보자는 결심을 하게 되었다.

이 글은 Next.js가 처음이신 분들께 조금이나마 도움이 될 수 있을 것이라고 생각한다.

 

비록 나는 여기 저기 파헤치느라 꼬질이가 되었지만 ...

 

꾸준히 증가하고 있는 다운로드 수 🙌

사전 지식 정리

Next.js에 대해 이야기할 때면 항상 같이 있는 키워드가 있다. 

바로, SSR(Server Side Rendering), CSR(Client Side Rendering)이다.

이야기 하기전 키워드에 대한 정의를 바로 짚고 넘어가보도록하자.

SSR은 초코송이 과자, CSR은 얼초 .. 라고요..? 🍫

추억의 얼초 ..

그렇다. 비유하자면 SSR은 초코송이, CSR은 얼초에 비유할 수 있다.

초코송이는 제조 과정에서 이미 초콜릿을 틀에 맞게 녹이고 굳혀서 막대 과자 형태를 만들어 판매한다.

반면 얼초는 초콜릿튜브, 모양틀, 막대과자를 팔아서 사먹는 사람이 직접 만들어 먹을 수 있도록 한다.

둘의 결과물은 똑같지만, "만들어내는 시점"에서 차이가 생긴다. 

 

이는 SSR과 CSR도 마찬가지이다.

SSR은 서버에서 페이지가 만들어지고 난 후 화면에 렌더링이 되는 반면,

CSR은 HTML, CSS, JS파일을 다운 받아 브라우저에서 그려내는 방식이다.

 

조금 더 내부적으로 동작하는 방식을 확인해보면 아래와 같다.

 

이런 SSR 방식이 뭐가 좋냐고?

바로, 검색 엔진 최적화(SEO)에 굉장히 유리하다는 것.

 

SSR 방식이 검색 엔진 최적화(SEO)에 유리한 이유.

아까 초코송이와 얼초의 비유를 조금 확장해보려고 한다.

초코송이를 팔면서 사람들이 카페 내부에서 수다도 떨 수 있도록 공간을 마련되어있는 A카페가 있고,

카페 내부에서 수다는 떨 수 없지만, 집에서 편하게 얼초를 만들어 먹을 수 있도록 판매하는 B카페가 있다고 하자. 

 

이럴때, 사람들은 어떤 카페를 더 선호할까?

아마 초코송이를 눈으로 볼 수 있고, 사람들이 맛있게 먹는게 눈앞에 보이는 A카페를 더 선호할 것이다.

왜냐하면, 눈 앞에 제공이 되어있으니까!!

 

 

검색엔진크롤러 역시도 마찬가지다.

눈 앞에 제공이 되어있는 것을 크롤러가 인식하고 검색어 상위에 노출 될 수있게끔 한다.

 

이 차이는 프론트엔드 성능 측정할 때도 확연하게 드러나는 것을 알 수 있다.

프론트엔드의 성능 측정 기본 3가지

  1. TTFB : 페이지가 처음 로드 되는 시점을 의미 === 초기 로딩 속도가 빠른 CSR에 유리.
  2. FCP : 사용자의 눈에 처음으로 페이지를 인식할 수 있는 시점을 의미한다.
  3. TTI : 사용자와 페이지가 처음으로 상호작용이 가능한 시점을 의미 === 미리 서버에서 페이지를 생성한 SSR에 유리.

아래 이미지를 통해서 조금 더 자세하게 볼 수 있다.

 

 

하지만 무조건 SSR이 좋다고는 할 수 없다.

주의해야할 점은 번들 사이즈가 커지면, TTI 속도가 느려지는데

이는 CSR과 마찬가지 단점을 가지게 된다.

 

SSR로 서버의 부하가 심해지는 경우도 있다.

데이터의 변화로 계속 서버에 요청을 하면, 부하가 심해지게 된다.

마치 A카페에 사람이 많아지게 되면 주문이 밀리게 되고, 과부하가 오는 것과 같다.

 

그래서 이를 적절히 때에 맞게 활용할 수 있어야한다.

TMI) Next.js 너 몬데 어렵냐 ... (ft. 모두가 공감하시죠?)

 

쉽게 시작 시점(index.js or index,ts)을 찾을 수 있었던 리액트와는 다르게,

Next.js는 어디서 어떻게 시작되는지 그 구조 조차 파악하기 어려웠다. (사실 지금도 어렵다.) 

이유는 간단하다. "프레임워크 라서."

 

그러니까 이게 무슨 말인가 하면, 라이브러리는 내가 필요할 때 원하는 대로 쓸 수 있지만

프레임워크는 이미 제공되어있는 것을 가져다가 쓰는 것이다.

 

가령 커피 머신을 사서 캡슐 커피를 만들땐 먹고 싶은 캡슐을 가져와 넣으면 되지만(라이브러리),

카페에서 먹는 커피는 점주나 알바생이 만들어주는 커피를 마셔야 한다. (프레임워크)

 

물론, 카페에서 먹는 커피도 간단한 옵션(샷 추가, 시럽추가, 디카페인)이 있지만 그 범위가 넓지는 않다.

 

 

Next.js의 의도도 마찬가지다.

"필요한 걸(자주 사용하는 걸) 너희에게 제공할테니 가져다써. 그럼 생산성이 높아질거야!"

라는 말을 내포하고 있다.

 

리액트를 더 자주 사용했던 나는 이때까지만 해도 아직 공감이 가는 단계가 아니었다.

그래서 지금 Next.js를 하나 하나 공부해보면서 그 실체를 파악해보려고 한다.

 

두둥 ! Next.js의 실체를 공개합니다 - !!

우선 전체를 살펴 볼려고 한다.

버전에 따라 변경된 폴더 구조

v12에서는 page router를 사용했다.

page라는 폴더 내에 [파일명].tsx라고 생성하면 그대로 url에 적용되는 방식이었다.

 

v13에서는 app router 방식을 사용하기 시작했다.

 

여기서 page.tsx를 폴더 내부에 작성하게 되면 폴더의 네이밍에 따라 경로가 생성된다.

main이라는 폴더 아래에 기존 page.tsx를 옮겼다.

 

그런데 여기서 한 가지 문제점을 발견할 수 있다.

폴더가 많아질 수록, 페이지가 증가할 수록

페이지에 대한 폴더 네이밍(ex. admin/page.tsx)과 관심사가 분리된 네이밍(ex. components, utils)구분이 어렵다.

 

게다가 만약 components 폴더 내부에 page.tsx라는 파일을 작성하게 되면,

https://{url 주소}/components라는 url이 생성 될 수 있다. 

 

그래서 v13에서는 이 문제를 해결할 수 있는 방식을 제공하였다.

Routung Group & Private Router

이 두 가지 방식을 통해서 우리는 쉽게 이 문제를 해결할 수 있다.

 

Routung Group

폴더명을 괄호로 감싸 하나의 그룹으로 만드는 방법이다.

아래와 같이 활용할 수 있다.

 

폴더 명을 (route)로 만들어 그 아래 페이지 폴더를 만든다.

그리고 그 내부에 page.tsx를 만들면 폴더 네이밍에 따라 경로가 생성된다.

 

Private Router

폴더 명 앞에 언더 바(_)를 붙이는 방식이다.

예를 들어 components라는 폴더 앞에 언더바를 붙여

_componetns이렇게 사용이 가능하다.

 

그리고 코드는 이렇게 사용된다.

// _components/button.tsx
export const Button = () => {
  return <button>버튼</button>;
};
// (route)/admin/page.tsx

import { Button } from "@/app/_components/button";

export default function Admin() {
  return (
    <main>
      <h1>admin</h1>
      <Button />
    </main>
  );
}

 

두 가지 방식 중 어떤 방식을 선택하든지 개발하는 사람의 마음이다.

참고로 필자는 Private Routing 방식을 더 선호한다.

VSC에서 meterial icon을 꾸며주어서 구분하기 쉽기 때문이다.

 

위 방식을 적용하여 아래와 같이 폴더 구조를 작성해보았다.

 

맺으며

앞으로 얘기할 다양한 주제를 이어서 담아볼 생각이다.

지난해 Next.js를 활용하면서 제대로 사용하지 못한 부분이 아쉬웠는데,

이번에 포스팅을 하면서 직접 개선을 해보려고 한다!