티스토리 뷰

'Next.js'는 프론트엔드 개발에 필수일까? 아니다.

프론트엔드 개발자를 포함해 웹 개발자는 백엔드에서 대용량 데이터를 잘 처리해서 프론트엔드에서 클라이언트를 동적으로 잘 활용하는 것이 우선이다.

 

그렇다면, 이직 준비에는 필수일까? 그럴 수도 있다. 많은 IT 기업에서 'React'와 함께 'Next.js'를 자격요건이나 우대사항에 기록해두고 있다.

 

'Next.js'는 개발에 필수는 아니지만, 이직에는 필수일 수 있다.

 

Next.js

그렇다면, 'Next.js'는 무엇일까?

'Next.js'는 React 기반의 프레임워크로, 서버 사이드 렌더링(SSR)과 정적 사이트 생성(SSG)을 쉽게 구현할 수 있도록 설계된 도구이다. Vercel에서 개발하였으며, 성능 최적화와 개발자 경험에 중점을 둔 기능을 제공하고 있다. 또한, React의 기능을 확장하여 대규모 웹 애플리케이션을 더 쉽고 효율적으로 개발할 수 있도록 돕는다.

 

React Next.js
라이브러리 프레임워크
클라이언트 사이드 렌더링 서버 사이드 렌더링

 

Next.js는 서버 사이드 렌더링으로 클라이언트에서 서버에 요청을 하면, 서버에서 자바스크립트 등 데이터를 클라이언트에 전달한다.

 

그렇다면, 서버 사이드 렌더링의 이점은 무엇일까? 속도가 빠르다는 것일까?

속도는 '처리 성능'과 '네트워크 성능'에 영향을 받는다. 이 때, 서버는 처리 성능이 개인 디바이스보다 뛰어나다.

 

기존의 방식을 보자면,

1. Client → 서버 측에 GET 요청
2. 서버 → Client 측에 HTML 전달
3. Client → 서버 측에 JavaScript 요청
4. 서버 → Client 측에 JavaScript 전달
5. Client → 서버 측에 API 요청 전달
6. 서버 → 데이터베이스 측에 데이터베이스 조회
7. 데이터베이스 → 서버 측에 데이터베이스 전달
8. 서버 → Client 측에 로직 처리 후 API 응답

 

기존의 방식에서 Next.js 방식으로 변경한다면?

1. Client → 프론트엔드 서버 측에 GET 요청
2. 프론트엔드 서버 → 백엔드 서버 측에 API 요청 전달
3. 백엔드 서버 → 데이터베이스 측에 데이터베이스 조회
4. 데이터베이스 → 백엔드 서버 측에 데이터베이스 전달
5. 백엔드 서버 → 프론트엔드 서버 측에 로직 처리 후 API 응답
6. 프론트엔드 서버 → Client 측에 HTML 전달

 

기존 방식에서 단순히 몇 단계만 줄은 것이 아니라, 클라이언트와 서버의 외부 통신에서 프론트엔드 서버와 백엔드 서버의 내부 통신으로 방식이 변경되어 외부에서 중요한 데이터를 접근할 수 없도록 할 수 있게 됐다.

 

간단하게 서버 사이드 렌더링의 장점과 단점을 알아보자.

장점 단점
SEO 최적화 서버 비용 증가
저사양 기기 지원 개발 복잡도 증가
API 은닉화 응답 시간 증가
브라우저 호환성 향상 서버 의존도 증가
FCP 성능 향상 페이지 전환 성능 감소

 

13 버전

왜 우리는 '13 버전'부터 사용해야 할까? 그 이유는 아래의 기능들을 13 버전부터 사용할 수 있기 때문이다.

 

  • App Router
  • React Server Component
  • Server Fetching

 

혹시, 'Page Router'와 'App Router'는 'getStaticProps()'와 'getServerSideProps()'와 관련해서 차이를 보인다.

 

이들은 'Page Router'의 기능들이다.

'getStaticProps()'는 'SSG(Static Side Generation)'으로 'next build(npm run build)' 시점에 실행하며 내용이 모두 채워진 '.html 파일'을 전달한다. 쉽게 말해, 빌드한 시점에 모든 내용을 받는다. 그리고 다시 'build' 할 때까지 유지가 된다. (추가 실행이 되지 않는다)

type Repo = {
	name: string;
    count: number;
}

export const getStaticProps = (async () => {
	const res = await fetch('...');
    const repo = await res.json();
    return { props: { repo } };
}) satisfies GetStaticProps<{ repo: Repo; }>;

export default function Page({ repo }): InterGetStaticPropsType<typeof getStaticProps> {
	return repo.count;
}

 

 

'getServerSideProps()'은 'SSR(Server Side Rendering)'으로 요청 시점에 실행되며, 동적으로 '.html 파일'을 생성한다. 그리고 요청 때마다 재실행한다.

type Repo = {
	name: string;
    count: number;
}

export const getServerSideProps = (async () => {
	const res = await fetch('...');
    const repo = await res.json();
    return { props: { repo } };
}) satisfies GetServerSideProps<{ repo: Repo; }>;

export default function Page({ repo }): InterGetServerSidePropsType<typeof getServerSideProps> {
	return repo.count;
}

 

그러나, 이를 사용하는 과정에서 불편한 점이 존재한다. 단점이라고 할 수도 있겠다.

 

바로, 무조건 최상단에 위치해야 한다. 사용하고자 하는 컴포넌트의 Root 컴포넌트에서 사용해야 한다.

그리고 기존 JavaScript, React가 없는 독자적인 코드고, 내부 컴포넌트에서는 동작을 예측하기가 어렵다.

 

'App Router'에서는 'getStaticProps()'와 'getServerSideProps()'가 아닌 'React Server Component'와 'Server Action'이 존재한다. 이 때, 알아두어야 할 것은 'React Server Component'은 React(18 버전 이상)에서 사용되는 것이고, 'Server Action'이 Next.js(13버전 이상)에서 사용되는 것이다.

 

위 처럼 정해진 이름을 사용해서 처리하는 것이 아니라 보일러플레이트 없이 순수 JavaScript를 사용하듯이 사용할 수 있다는 것이 장점이다.

export default async function Page() {
	const res = await fetch('...');
    
    return res.count;
}

 

그래서 우리는 왜 13 버전(이상)을 선택해야 할까?

12 버전에서 13 버전의 업데이트는 혁신적인 변화를 이루었지만, 그 이후부터는 내부 코드 최적화와 고도화를 진행하였기 때문에 13 버전 이상을 선택하는 것이 좋은 선택이다.