미새문지

24.10.08 day76 Next.js 본문

개발 TIL

24.10.08 day76 Next.js

문미새 2024. 10. 8. 23:51
728x90

Next.js 즉, 넥스트는 React 기반의 프레임워크로, React에 비해 여러 추가 기능과 최적화를 제공하여 개발 효율성과 성능을 향상시킨다고 한다. 특히 넥스트는 리액트의 모든 기능을 제공하면서 클라이언트사이드 렌더링(CSR)이였던 리액트와 달리 서버사이드 렌더링(SSR)을 지원하고 폴더 구조에 기반한 라우팅, 정적 사이트 생성(SSG)등의 더 많은 기능을 내장하고 있다.

최근 개발하는 웹 사이트의 경우 넥스트와 타입스크립트를 함께 사용하는 것이 추세라고 들어 학습하려고 한다.

 

넥스트의 특징

넥스트의 기본 구조

  • 넥스트는 위에서 말한대로 폴더를 인식해 pages 폴더 안의 파일들이 라우팅으로 매핑되서 페이지 경로로 이어진다.
    • 예시로 pages/login.js는 /login으로 경로가 지정되어 유지보수할 때 용이하다.
  •  _app.js파일은 기존의 리액트와 같이 전체 페이지를 감싸는 커스텀 레이아웃 파일이며, 공통 레이아웃이나 글로벌로 설정하는 css나 인터페이스 등을 설정할 수 있다.
  • _document.js파일은 HTML 문서 구조를 커스텀할 수 있는 파일로, 서버에서 처음 렌더링 될 때 한 번만 실행된다.
  • public폴더는 기존 리액트와 같이 이미지, 폰트, 비디오 등을 저장해놓는 폴더이다.

 

서버사이드 렌더링 (SSR, Server-Side Rendering)

넥스트의 가장 큰 특징 중 하나는 ssr을 기본적으로 지원한다는 것인데, ssr은 웹 페이지가 서버에서 먼저 렌더링되어 클라이언트에게 전송된 후, 사용자가 페이지를 빠르게 볼 수 있게 해준다. 이는 SEO(검색 엔진 최적화)에도 유리하며, 특히 검색 엔진이 자바스크립트를 실행하기 전에 HTML 콘텐츠를 읽을 수 있기 때문에 더 나을 수 있다.

 

ssr의 동작 방식은 페이지를 요청하면, 서버가 해당 페이지를 렌더링하여 완전한 HTML 파일을 클라이언트에 전달하고 클라이언트에서 페이지가 로드된 후, 리액트는 이 HTML에 대해 "Hydration" 과정을 거쳐 애플리케이션을 활성화한다.

 

Hydration

여기서 hydration은 ssr과 csr에서 자주 사용되는 개념이며, ssr로 설명하면 서버에서 미리 렌더링된 HTML을 브라우저가 받아온 후, 그 위에 클라이언트 측 자바스크립트 코드를 추가로 실행하여 동적인 기능을 활성화하는 과정이다.

 

Hydration의 장점

  • 빠른 초기 렌더링: 서버에서 미리 렌더링된 HTML을 제공하므로, 사용자는 페이지를 빠르게 볼 수 있기 때문에, 초기 로딩 시간을 줄이는 데 유리하다.
  • SEO 개선: 서버에서 HTML을 완성한 상태로 제공하기 때문에 검색 엔진 크롤러가 더 쉽게 콘텐츠를 이해할 수 있어 SEO 성능이 좋아진다.
  • 사용자 경험 개선: 초기 화면이 빠르게 표시된 후, 클라이언트 측의 자바스크립트가 추가되어 상호작용을 제공하므로, 사용자는 페이지가 점진적으로 "완성"되는 느낌을 받는다.

Hydration의 단점

  • 성능 이슈: 서버에서 생성된 HTML을 클라이언트 측에서 다시 한 번 자바스크립트로 처리해야 하기 때문에, 큰 페이지나 복잡한 UI일 경우 클라이언트 성능에 부담을 줄 수 있다.
    • 특히, Hydration이 끝나기 전까지 사용자는 상호작용이 불가능할 수 있다.
  • 중복 작업: 서버에서 이미 HTML을 생성했는데, 클라이언트에서 동일한 작업을 한 번 더 수행해야 하기 때문에, 이로 인해 중복 계산이 발생할 수 있다.
  • 복잡한 유지보수: 서버와 클라이언트 양쪽에서 동일한 코드를 관리해야 하므로, 개발이 복잡해질 수 있다.

단점이 명확하긴 하지만 Hydration은 필요한 요소인데 그 이유는 ssr의 정적 페이지에 동적 기능을 추가할 수 있기 때문이다. ssr만으로는 사용자가 페이지와 상호작용할 수 없으므로, 자바스크립트로 활성화를 해야한다.

Hydration은 초기 HTML이 클라이언트에 로드된 직후 발생하며, 브라우저가 서버로부터 받은 HTML을 먼저 보여주고, 이어서 자바스크립트가 로드되면 그 시점에 리액트 등의 프레임워크가 HTML을 분석하고 기존 DOM을 변경하거나 추가 동작을 연결하면서 Hydration이 완료된다.

 

정적 사이트 생성 (SSG, Static Site Generation)

위의 Hydration이 ssg를 통해 제공된 정적 파일을 동적으로 활성화하는 과정이다.

넥스트는 정적 사이트 생성을 통해 사전에 HTML 파일을 생성할 수 있는데, 이는 성능 최적화에 매우 유리하며, 서버 요청 없이도 빠른 로드가 가능하다.

 

ssg의 동작 방식은 빌드 시점에 페이지를 미리 렌더링하여 정적 HTML 파일을 생성한다. 이 방식은 블로그나 문서 페이지와 같은 자주 업데이트 되지 않는 방식에 적합하다.

ssg는 정적 파일이기 때문에 서버 부하가 적고, 매우 빠른 응답 속도를 제공할 수 있으며, 넥스트에서는 getStaticProps라는 함수를 통해 ssg에서 데이터를 가져올 수 있다고 한다.

 

자동 코드 분할

넥스트는 페이지 단위로 코드가 분할되어, 사용자가 방문한 페이지에 필요한 코드만 로드한다. 이는 초기 로딩 속도를 빠르게 하고, 사용하지 않는 페이지의 코드를 불러오는 시간을 줄여줘 유용한 기능이다.

이로 인해 페이지별로 필요한 자바스크립트 파일만 로드하기 때문에 성능이 최적화되고, 사용자가 필요한 리소스만 로드하도록 하여 웹 애플리케이션의 전체 성능을 개선할 수 있다.

이미지 최적화

넥스트는 내장된 이미지 최적화 기능을 제공하며, next/image 컴포넌트를 사용하면 자동으로 이미지 크기가 조정되고 lazy loading(지연 로딩)과 WebP 형식의 변환 등이 가능해진다.

기존에 이미지 크기를 맞추느라 일일히 지정했던 것과 다르게 넥스트에서는 이미지에 대한 크기를 자동으로 지정해주기 때문에 코드가 깔끔하게 작성될 것 같다.

 

하지만 사용하기 매우 편리한 넥스트도 단점이 존재한다.

넥스트의 단점

복잡한 서버 설정

  • 넥스트는 서버사이드 렌더링을 지원하기 때문에 서버 설정이 더 복잡해질 수 있는데, 서버나 서버리스 환경에서 호스팅할 때 특히 추가적인 설정과 관리가 필요하다. csr인 리액트와 달리, 서버에서 실행되는 코드와 클라이언트 사이드 코드를 모두 관리해야 하기 때문에 리액트보다 까다롭다.

SSR의 성능 이슈

  • ssr을 사용할 경우, 서버에서 렌더링된 페이지를 매번 요청에 따라 생성해야 하기 때문에 트래픽이 많은 경우 서버 부하가 증가할 수 있다. 이는 서버 자원에 민감하며, 성능 최적화를 위해 캐싱 전략을 잘 설계해야 한다.
  • 즉, 활동량이 많은 커뮤니티나 쇼핑몰 같은 경우 트래픽이 많기 때문에 서버 부하가 증가할 수 있어, 이 부분에선 ssr보다 csr이 더 나은 성능을 보일 수 있다.

프로젝트 크기

  • 넥스트는 리액트에 비해 강력한 기능을 제공하지만, 범위가 적은 단순한 프로젝트나 SPA(Single Page Application)를 만드는 경우는 과한 선택일 수 있다.

넥스트에 의존적

  • 넥스트는 리액트 위에 구축된 프레임워크지만, 자체적인 규칙과 구조를 가지고 있기 때문에 넥스트 기능을 많이 사용하며 의존적이게 되면 넥스트가 아닌 다른 환경으로 전환하는 것이 어려울 수 있다. 하지만 이 부분은 전체적인 패치가 가해지는 대규모 프로젝트에서나 적용되기 때문에 사이드 프로젝트나 소규모의 프로젝트에선 걱정할 필요가 없다.
 

 

단점이 명확한데도 많이 사용되는 이유는 사이트 운영에 매우 중요한 성능 최적화와 확장성이 훨씬 좋기 때문이다.

 

넥스트를 설치하게 되면 리액트와 다르게 여러가지 설정하는 부분이 있다.

바로 넥스트의 편의성이 드러나는데 타입으로 인한 버그 방지를 위해 타입스크립트가 거의 필수요소지만 해당 부분을 알아서 설치를 해준다. 이어서 코드 퀄리티를 보장해주는 eslint도 자동 적용해줘 매우 편리하다.

테일윈드의 경우 css의 프레임워크인데 본인은 불마나 테일윈드를 한 두번밖에 안써봐서 안 익숙하기도 하고 직접 css를 만지는걸 좋아해서 굳이 사용하진 않았다.

src/ 폴더 설치는 프로젝트의 기본적인 틀을 제공해주기 때문에 설치했고, app router 부분이 넥스트의 장점인 폴더 라우팅 요소이다. 이걸 사용함으로써 폴더 구조에 따라 라우터 경로가 지정된다.

import alias는 매번 파일의 경로를 절대 경로로 지정해주는게 아닌 public폴더처럼 특정 지점부터 파일을 찾을 수 있게 해주는 요소이므로 이 기능도 코드 최적화에 유리하다.

세팅을 다 결정하면 넥스트가 설치된다.

 

그리고 넥스트는 npm run dev로만 실행을 하는데, 이 이유는 개발 환경과 프로덕션 환경의 구분을 명확하게 하기 위해서이다.

개발 단계에서만 run dev를 사용하고 실제 프로덕션 환경에서는 다른 명령어를 통해 최적화된 버전으로 앱을 배포하기 위해 분류됐다.

리액트도 직접 구분지어 작성하기도 하지만, 넥스트는 기본적으로 분류를 해주기 때문에 이 부분에서도 편의성이 작용한다.

 

또한 개발에 npm run dev를 사용하는 이유 중 하나는 개발에 필요한 기능을 활성화 할 수 있기 때문인데

  • 핫 리로딩 (Hot Reloading): 파일을 수정할 때마다 변경 사항을 자동으로 감지하고, 페이지를 새로 고침하지 않고도 수정된 내용을 실시간으로 반영한다.
  • 빠른 피드백: 변경 사항을 즉시 반영해주므로 개발자가 빠르게 결과를 확인하고 작업할 수 있다.
  • 에러 메시지와 디버깅: 개발 모드에서는 더 많은 디버깅 정보와 에러 메시지를 제공해 주어 개발자가 문제를 쉽게 찾고 해결할 수 있다.

이 부분은 리액트에선 확장 프로그램을 설치하거나 세팅을 했어야 사용할 수 있지만 넥스트는 npm run dev에 해당 기능을 사용할 수 있어 개발이 매우 편해진다.

 

반대로 프로덕션 환경에선 npm run start를 사용해 최적화된 애플리케이션을 실행할 수 있다. npm run build를 사용해 애플리케이션을 빌드하게 되면 프로덕션 환경에 맞춰 코드 분할과 트리 쉐이킹(불필요한 코드 제거) 등의 기능이 작동하기 때문에, 코드가 최적화되고 ssr과 ssg를 고려한 최종적인 정적 HTML 파일이 만들어진다.

빌드된 파일을 npm run start로 실행하면 빌드된 정적 파일들을 서버에서 제공하기 때문에 최적화된 성능으로 작동하게 된다.

 

이러한 실행 코드가 분류되는 이유는 각 기능들이 다른 환경에 도움되지 않는 기능이기 때문이다.

개발 환경에선 매번 테스트를 위해 불필요한 코드가 생성되고 매번 코드를 바꾸며 기능 구현을 해야 하지만 npm run start에 있는 트리 쉐이킹같은 기능들이 굳이 작동할 필요가 없기 때문에 사용할 필요가 없다.

반대로 프로덕션 환경에선 이미 완성된 코드를 압축하며 최적화하기 때문에 상세한 에러탐지 기능이 필요가 없고 실시간 반영도 의미가 없게 된다.

 

예전에 넥스트를 한번 써본적이 있었는데 그 땐 넥스트의 중요성을 크게 느끼진 못했다. 그 당시 본인은 자바스크립트에 대한 학습도 너무 부족한 상태에서 운좋게 참여한 프로젝트가 넥스트+타입스크립트를 사용했기 때문에 어떻게든 코드짤려고 발악했었다. 이 과정에서 자바스크립트에 대한 지식이 너무 부족하다 생각해 리액트부터 학습하며 리액트만 사용했었다. 하지만 어느정도 프론트에 대해 이해를 하기 시작하니 프레임워크에 대한 기능 차이가 크게 돋보이게 되어 이제라도 학습해보려 한다.

728x90