Next.js 그거 어떻게 하는 건데.

Wynn
14 min readSep 26, 2021

--

Next.js

최근 새로운 팀에 합류하고 온보딩 프로세스를 진행하고 있다. 제품에 대한 이해도를 높이기 위한 과정도 있고, 팀 자체적으로 진행하는 온보딩도 있는데 이번에 작성하게 될 글은 팀 자체적으로 진행하는 온보딩 프로세스 중 하나인 API as a Service로 제공되는 commerce API를 활용해 쇼핑몰 만들기를 하면서 Next.js를 사용해봤던 경험을 토대로 정보를 공유해보려고 한다.

Next.js

Next.js는 vercel 팀에서 만든 정적 페이지와 서버사이드 렌더링을 하이브리드하게 구현할 수 있는 유연한 React Framework이다. 특히 국내에서는 SEO 최적화를 위해서 많이 이용하는 걸로 알려져있다.

Next.js는 공식문서의 Showcase에서 Next.js를 사용하는 기업에 대해 소개하는데 많은 유명 테크 기업에서 사용하고 있기 때문에 이미 충분한 검증이 이루어진 프레임워크라고 볼 수 있다.

GitHub Copilot
TikTok

뿐만 아니라 TicketMaster, realtor 등 많은 e-commerce 기업에서도 사용하고 있는 듯 하다.

나는 특히 Zero Config를 지향하는 vercel 팀에서 만드는 프로덕트를 좋아하는데 개발을 진행하면서 늘 마찰을 빚는 배포나 통합 파트에서 매끄러운 개발자 경험을 제공하기 때문이다. Next.js와 함께 vercel 플랫폼을 사용한다면 GitHub과 연동하여 마치 매직처럼 배포를 1분 만에 수행할 수 있다. 또한 작업사항을 main 브랜치에 병합하기 위해 PR을 날리면 페이지 내에서 pre-deploying을 수행하여 preview 기능을 제공하는데 이게 또 기가 막힌다. 협업 관점에서 정말 편리한 기능이다.

Why Next.js

나 역시도 프론트엔드 파트에서 업무를 진행하고 있지 않고 있기 때문에 Next.js를 직접 사용해보기 전까지는 막연히 Single Page Application(이하 SPA)의 강점을 살리면서 Server Side Rendering(이하 SSR)까지 수행할 수 있는 모던한 프레임워크로 알고 있었고, 사용하기에는 조금 러닝커브가 있는 프레임워크라는 생각을 했었다. 하지만 이건 반은 맞고 반은 틀린 말인거 같다.

Next.js는 공식 문서에서 아래와 같이 언급한다.

Next.js gives you the best developer experience with all the features you need for production: hybrid static & server rendering, TypeScript support, smart bundling, route pre-fetching, and more. No config needed.

정말 맞는 말이다. Next.js에서 내게 많은 설정을 요구하지 않았고, 그럼에도 불구하고 필요한 기능들을 제공해줘서 좋은 개발 경험을 느꼈다. 어찌보면 당연한게 Next.js는 React를 보다 더 편리하게 사용할 수 있도록 한번 더 추상화하여 개발자에게 고수준(high level)의 기능들을 제공하기 때문이다. 심지어 프로젝트 초기화 시 입력하는 커맨드도 create-next-app 으로 React에서 제공하는 CRA와 거의 동일한 솔루션으로 제공된다.

즉, 사용이 어렵다기 보다는 Next.js에서 추가적으로 제공하는 기능들이 있어서 그렇게 느껴지는 거 같다. 이를 반증하듯 React를 완벽하게 A-Z 개발을 진행해 본 경험이 없던 나인데 이번 온보딩 프로세스를 잘 완주했다 :)

Next.js가 자신있게 소개하는 기능들은 다음과 같다.

  1. Image Optimization
  2. Zero Config
  3. Hybrid: SSG and SSR
  4. TypeScript Support
  5. File-system Routing
  6. API Routes
  7. Code-splitting and Bundling

이외에도 더 많은 기능을 제공하니 자세한 정보를 보고 싶다면 Next.js 공식 문서를 참고하자.

내가 느꼈던 Next.js

아무래도 전 직장에서 조금씩 프론트엔드 작업을 할 때가 있었는데 그 때 운영해 본 경험이 있어서 선택했던 이유가 가장 크긴 하다. 그래도 몇 가지 고려했던 점들에 대해서 간략하게 소개해보려고 한다.

나는 Next.js를 사용하면 생산성 측면에서 꽤 많은 이점을 얻을 수 있다고 생각한다. 일단 Zero-config로 뭔가를 뚝딱 만들어낼 수 있다는 게 정말 좋다.

Deploy

일단 앞서 언급했듯 Next.js + vercel을 사용하면 배포가 정말 쉽다. GitHub 로그인하고 원하는 Repository를 선택해주고, 환경 변수 입력해서 배포하면 끝이다.

30초 컷

아래는 vercel의 pricing 정책이다. vercel에 개인으로 프로젝트를 배포 및 운영할 때는 비용이 발생하지 않으니 참고바란다. 즉, vercel + Next.js + mongoDB(atlas)를 삼위일체로 사용하면 Cloud 서비스를 제공하는 AWS, Azure 등의 IaaS 없이도 코드를 돌릴 수 있다. 공짜 너무 좋아.

vercel pricing

다만 GitHub Organization에서 프로젝트를 운영할 경우 비용이 발생하긴 하지만 이를 우회적으로 무료로 사용하는 방법이 있긴 하다. 추천하는 방법은 아니지만 그래도 가볍게 시작하는 팀 프로젝트일 경우 분명 니즈가 있을 거라 생각되어 노션에 짧게 공유해두었으니 필요하다면 참고해도 괜찮을 거 같다.

File System based Routing

Next.js는 기본적으로 페이지 라우팅을 파일 시스템을 기반으로 제공한다.

예를 들어 /pages/orders/thanks.ts 경로에 아래처럼 파일을 생성한다고 해보자.

/pages/orders/thanks.tsx

브라우저에 해당 파일이 위치하고 있는 경로를 브라우저 주소창에 도메인 뒤에 suffix로 붙여주면 페이지가 렌더링된다.

주문하신 경로에 페이지 배달이 완료되었습니다.

Plain React로도 라이브러리를 사용해 Route 기능을 활용할 수 있지만 기본적으로 제공하니 따로 설정할 필요도 없고 개인적으로 파일 경로대로 보여주는게 조금 더 직관적인 느낌을 받았다. 물론 Next.js에서는 이 방식대로 강제하기 때문에 쓰기 싫어도 써야한다는게 단점일 수는 있겠다.

API Routes

Next.js는 /pages/api 경로에 API 핸들러를 생성하면 File system based routing을 통해 Serverless Function을 사용할 수 있다.

간단한 예로 /pages/api/hello.ts 파일을 생성하고 아래와 같이 API 핸들러를 작성해주면 https://domain-name.com/api/hello 로 통신했을 때 해당 json 정보를 받을 수 있다.

/pages/api/hello.ts

이 기능 덕분에 Client, Server 모두 모놀리틱한 구조로 프로그래밍이 가능한 점과 배포 역시 한번에 할 수 있기 때문에 신경써야할 포인트가 크게 줄어든다. 이로써 좀 더 프로그래밍에 집중할 수 있게 되니 생산성에 큰 이점을 얻는다.

모든 API를 완벽한 Production을 목적으로 사용하기에는 Serverless Function이 Stateless한 구조이기 때문에 DB 커넥션을 유지하기 어렵고, 측정해보지는 않았지만 Serverless 아키텍처의 고질적인 Cold Start 문제도 있으니 개인적으로는 간단한 프로토타입을 만들 때는 추천할 수 있을 거 같다.

또한 Next.js 자체에서 제공하는 미들웨어들은 굉장히 제한적이기 때문에 미들웨어를 만들어 핸들러를 커스텀하기 위해서는 약간의 우회책을 써야하는 점이 조금 아쉽긴 하다. 구글링을 해보니 커스텀 미들웨어를 만들고 이걸로 핸들러를 wrapping하는 형태로 사용하는 사람들이 꽤 있었다. 이게 아니면 next-connect라는 라이브러리를 써야했는데 나는 dependency 늘리기도 싫고, 귀찮아서 그냥 다 인라인으로 때려박았다.

혹시나 커스텀 미들웨어를 사용해보고 싶다면 이 블로그 글을 참고해보면 괜찮을 거 같다.

Pre-rendering

Next.js는 기본적으로 빌드 타임에 HTML 파일을 생성하여 모든 페이지에 대해서 pre-render를 지원한다. 이는 퍼포먼스 향상과 SEO 최적화에 도움을 준다. 글을 읽는데 익숙하지 않을 수 있으니 들어가기에 앞서 SPA와 Static Generated SSR의 차이를 간단하게 살펴보고 넘어가려고 한다.

SPA

Client only SPAs (source: https://bit.ly/2XNTW5s)

기본적으로 아무 옵션없이 React를 사용할 경우 요청이 들어오면 JS 파일이 로드되면서 빈 페이지에 React Component가 렌더링되고 서버에 데이터를 요청한 후에 응답을 받으면 Hydration을 진행한다.

Static generated SSR

Statically exported sites (source: https://bit.ly/2XNTW5s)

Next.js의 경우 빌드 타임에 pages 폴더 안에 있는 코드를 토대로 HTML 파일을 미리 생성하고, 이를 바로 렌더링 해준다. 바로 정적 파일을 사용자에게 보여주니 유저 Latency가 짧을 수 밖에 없다. 물론 이는 아래서 다뤄볼 getStaticPropsgetServerSideProps 에 따라서 다르지만 설명을 위해 지금은 이렇게만 알고 넘어가려고 한다.

Next.js에서 중요한 개념은 getStaticPropsgetServerSideProps 이다. 과거에는 9.3 이전 버전에서는 getInitialProps 를 사용했고 현재도 지원은 하고 있지만 getStaticPropsgetServerSideProps 이 두 가지를 사용하도록 권장하고 있다.

Static Generation

Static Generation (source: https://nextjs.org/learn/basics/data-fetching/two-forms)

Static Generation은 위에서 언급한대로 간단하다. 빌드 타임에 HTML을 생성하고 해당 HTML을 재사용한다.

정적 생성을 위해서는 pages 경로 안에서 getStaticProps 함수를 export하여 사용하면 된다.

/pages/api/products.tsx

getStaticProps 를 쓰면 CMS에서 데이터를 생성하거나 수정했을 때 반영이 안되는거 아니냐고 할 수도 있는데 이것도 맞는 말이다. 하지만 그럴 경우 revalidate 옵션을 주면 Incremental하게 정적 페이지를 재생성할 수 있다. 해당 옵션으로 10초를 준다면 요청 기준 매 10초마다 revalidation을 수행한다.

/pages/api/products.tsx

Static Generation은 거의 대부분의 경우에 사용하면 된다. 쇼핑몰로 따지면 소개 페이지나 도움말 그리고 상품 리스트도 revalidate 값을 적당히 줘서 사용하면 SSR보다 훨씬 효율적이다.

SSR

Server-side Rendering (source: https://nextjs.org/learn/basics/data-fetching/two-forms)

서버 사이드 렌더링은 per request로 서버와 통신한다. pre-rendering을 지원하기 때문에 SEO 최적화도 가능하긴 하지만 매 요청마다 서버와 직접적으로 통신을 하다보니 서버에 부하를 줄 수 있고, 아울러 유저 Latency도 Static Generation 방식보다는 오래 걸린다. 공식 문서를 보면 vercel team에서도 직접 Static Generation을 추천한다고 언급하고 있다. 하지만 중요한 데이터가 실시간으로 즉각 반영되야 한다면 SSR 옵션을 사용하는게 좋다. 이를테면 상품 상세페이지에서 수량 정보 등 변동되는 중요한 정보들을 디스플레이하고 있다고 가정했을 때 실시간 반영을 위해 SSR을 사용할 수도 있을 거 같다. 하지만 기본적으로는 Static Generation에 revalidate를 짧게 줘서 진행하는게 가장 좋긴 하다. SSR 기능을 사용하기 위해서는 getServerSideProps 함수를 export 해주면 사용 가능하다.

/pages/api/products/[id].tsx

일단 Static Genration을 사용하든 SSR을 사용하든 데이터를 pre-fetching 해온다는 점이 클라이언트 개발을 하면서 편했던 거 같다. 개인적으로 이렇게 data fetching을 수행하면 코드가 깔끔해지는 거 같다.

React + axios

/pages/index.tsx

Next.js (물론 늘 이렇지는 않지만 😭)

/pages/index.tsx

마무리하며

새로운 팀에 합류하고 내가 써보고 싶은 걸 기술을 업무 시간에 마음껏 써볼 수 있어서 정말 만족스러운 온보딩 과제였다 😁

vercel/next.js

과제 중간에 소소하게 문서에 있는 예제 소스코드를 수정하여 Contribution 할 수 있는 기회가 있어서 요것도 같이 진행했는데 아무래도 대규모 오픈소스이다보니 기분이 좋았다 😇

예전에는 꺽쇠기피증이 있어서 프론트엔드 개발을 썩 좋아하진 않았는데 요즘에는 하면 할수록 탐구해야 할 것도 많고, 재미도 있는 거 같다.

여담으로 roadmap.sh에서 제공하고 있는 2021 프론트엔드 개발자 로드맵을 살펴보면 Static Site Generators 부문에서 Next.js와 함께 GatsbyJS도 추천되고 있다.

roadmap.sh

다만 데이터를 받아올 때 GraphQL을 사용해야하기 때문에 서버 쪽에서 데이터를 보내줄 때 조금은 러닝커브가 있지만 컨텐츠가 그렇게 많지 않고 동적인 액션이 크게 필요없다면 Gatsby도 좋은 선택인 거 같다. 미디엄은 좀 더 글을 큐레이션하는 느낌에 가까워서 다음에 프론트엔드 작업이 그리워질 때 쯤이면 낙서장으로 쓸 블로그도 한번 만들어보면 좋을 거 같다.

끝으로 얕게 배운 지식을 정리한 내용이니 늘 피드백은 환영입니다 🙏

References

--

--