서론
주로 사용하던 React 기술을 기반으로 만든 프레임워크인 Next.js에 대한 궁금증이 생겼습니다. 대부분의 서비스들이 React로 이루어진 가운데 NexR 홈페이지는 Next.js를 사용해 구현이 되어 있다는 것을 알게 됐고 왜 Next.js를 채택하게 되었을지 의문점을 가졌습니다. React와 어떠한 차이점이 있고 두 기술의 장단점은 무엇이며 앞으로 서비스를 제공할 때 어떤 기술을 선택하는 것이 좋을지에 대한 연구를 진행하기로 했습니다.
또, React와 Next.js는 기본적으로 라이브러리와 프레임워크라는 큰 차이점이 있습니다. 라이브러리와 프레임워크를 서비스에 사용했을 때 어떤 점이 다르게 작용하고 사용 방법은 어떠한지에 대한 연구도 진행해 보았습니다.
관련기술
Next.js의 특징들을 알아보기 전, 전체적인 웹 렌더링 방식에 대한 지식이 있어야 합니다. SSR을 주력으로 삼는 Next.js에 대해 더 자세히 알기 위해 웹 렌더링 방식에 대한 리서치를 조사했습니다.
렌더링 방식은 크게 CSR, SSR, SSG로 나누어져 있고 각각의 특징들에 대해 알아보겠습니다.
1.
CSR (Client Side Rendering)
•
사용자가 웹 사이트에 접속하면 브라우저는 서버에서 받은 html 파일을 화면에 로딩합니다.
º html에 담긴 정보는 현저히 적기 때문에 사용자는 원하는 정보를 받기까지 더 기다려야 합니다.
•
다시 브라우저는 서버에게 js 파일을 요청하게 되는데 서버에서 보내준 js 파일은 라이브러리 및 소스 코드 등을 모두 포함하기 때문에 용량이 큽니다.
•
js 파일을 다운로드 후 완성된 화면을 사용자에게 보여줍니다.
→ js 파일의 크기가 매우 클 경우 사용자는 html이 그려주는 빈 화면만 보게 되는 문제점이 발생합니다.
낮은 SEO(Search Engine Optimization)
검색 엔진은 HTML 문서를 분석해 검색을 빠르게 할 수 있도록 도와주는 기능을 말합니다. 하지만, React와 같은 CSR 프로젝트의 index.html 코드는 body에 담고있는 내용이 매우 간략하며 적습니다. 내용이 적기 때문에 검색 엔진들이 웹 페이지를 분석하는 데 어려움을 느끼고 그 결과 SEO가 상대적으로 낮습니다.
2.
SSR (Server Side Rendering)
기존 CSR의 문제점인 사용자가 빈 화면만 보게 되는 경우를 보완하기 위해 나온 렌더링 방식
•
사용자가 웹 사이트에 접속하면 서버는 최소한의 js 코드를 담은 html 파일을 브라우저에 전송해 바로 사용자에게 화면으로 보여주게 됩니다.
º 모든 동적 요소를 담은 js 파일은 다운로드 되지 않았기 때문에 사용자는 화면과 인터랙션 할 수 없습니다.
•
그 후 서버에 동적 요소를 담은 js 파일을 요청해 다운로드 후 hydration을 진행합니다.
→ 사용자에게 첫 화면을 빠르게 보여줄 수 있는 장점이 존재합니다.
높은 SEO(Search Engine Optimization)
완성된 HTML 파일을 서버에서 받아오기 때문에 HTML 파일이 담고 있는 정보가 상대적으로 많습니다. 그래서 CSR보다 더 효율적인 SEO가 가능합니다.
3.
SSG (Static Site Generation)
미리 생성한 정적인 페이지를 서버에 저장해두고 사용하는 방식입니다. 새로고침마다 새로운 데이터를 불러오며 서버에 과부하를 주는 SSR의 단점을 보완할 수 있습니다.
ex) 모든 사용자에게 같은 화면이 보여 동적으로 생성할 필요가 없는 블로그나 소개 페이지 등에 사용합니다.
가설
React를 기반으로 만든 프레임워크이기 때문에 모든 방면에서 Next.js가 React보다 우수한 결과를 낼 것이라고 생각했습니다. 먼저 제가 생각한 두 기술의 차이점을 나열해 보았습니다.
React
React는 라이브러리로써 개발자가 코드로 직접 호출해야 합니다. 유용한 기능을 제공하긴 하지만 나머지 기술을 모두 개발자에게 맡긴다는 문제점이 있습니다. 그래서 개발자가 React를 처음부터 구축하기 위해선 시간과 노력이 상대적으로 많이 필요합니다.
Next.js
Next.js는 React로 만든 SSR 프레임워크이며, CSR과 SSR, SSG 모두 지원합니다. Next.js는 프레임워크이기 때문에 개발자의 코드를 호출하고 프레임워크의 문법과 구조에 따라야 한다는 특징이 있습니다. React에 필요한 도구를 제공하고 프로젝트에 기능 및 최적화를 제공해 줍니다.
SSG 방식을 사용하면 웹 사이트를 게시하기 전 페이지를 미리 생성할 수 있고, SSR을 사용하면 사용자가 요청할 때 서버 측에서 모든 코드를 실행하는 것이 가능합니다. React의 CSR 기능도 사용할 수 있어 React Hook으로 코드 구현이 가능하다는 장점도 있습니다.
즉, Next.js는 CSR만 지원하던 React-script와는 달리 CSR, SSR, SSG를 모두 지원해 React를 사용했을 때보다 성능을 향상 시킬 수 있다고 생각했습니다.
선행작업
Next.js를 사용하기 위한 설치 및 실행 방법에 대해 알아보았습니다.
설치방법
실행방법
•
index.js 파일에서는 무조건 함수에 export default를 해주어야 합니다.
•
함수의 이름은 중요하지 않지만 파일의 이름이 라우터의 주소를 의미하게 됩니다.
분석과정 및 결과
1.
Pre-rendering
Next.js는 모든 페이지를 기본적으로 pre-rendering 합니다.
Pre-rendering 적용
•
처음 HTML만 로드된 상황에서도 화면의 많은 부분이 보여지게 됩니다.
•
JavaScript까지 로드되면 hydration 되어 사용자와 인터랙션이 가능해집니다.
•
pre-rendering을 하게 되면 JavaScript를 실행하지 않아도 HTML로 화면을 볼 수 있기 때문에 SEO도 효율적입니다.
Pre-rendering 미적용
•
처음 HTML만 로드된 상황이라면 화면이 거의 보이질 않습니다.
•
JavaScript가 로드 되어 실행돼야 사용자가 화면을 볼 수 있습니다.
Next.js가 제공하는 Pre-rendering 방식
•
SSG : 빌드 타임에 pre-render (서버에 부화가 덜 하기 때문에 더 추천하는 방법입니다.)
•
SSR : 요청 타임에 pre-render
2.
Next.js 파일 구조
Next.js는 프레임워크이기 때문에 정해진 파일 구조에 따라야 합니다. 각 파일별로 어떤 특징을 갖고 있으며 어떤 기능을 보여주는지에 대해 알아보겠습니다.
Pages
•
pages 안에 있는 파일은 URL과 일대일로 매칭됩니다.
º ex) pages/index.js는 / 주소를 갖게 되고, pages/test.js는 /test 주소를 갖게 됩니다.
•
모든 페이지를 포함할 수 있는 _app.js 파일 생성이 가능합니다.
º Component와 pageProps를 props로 받게 됩니다.
Layout
•
component 폴더에 주로 만들고 Pages의 모듈화를 위해 사용합니다.
•
페이지가 아닌 컴포넌트이기 때문에 SSR이 불가능합니다.
•
Layout 안에서 children으로 전달해 공통 레이아웃으로 감싸주는 방식입니다.
일부 컴포넌트에만 공통적인 레이아웃을 만들고 싶다면?
기존 CSR 페이지 UI
•
components 폴더 속 SubLayout.js 파일을 생성합니다.
º children 요소 위에 항상 Home 바로가기가 있는 코드가 있다고 가정합니다.
•
SubLayout을 사용하고자 하는 페이지에서 getLayout 함수를 선언합니다.
º CSR 페이지 위에 Home 바로가기 링크를 넣고자 합니다.
•
_app.js에서 getLayout 유무로 분기처리를 합니다.
º 없을 경우 Home 바로가기 링크가 없는 페이지 UI를 반환합니다.
SubLayout을 적용한 CSR 페이지 UI
Images
Next.js가 제공하는 최적화 Image Component Util입니다.
•
Improved Performance (성능 향상)
•
Layout Shift 방지
º 폰트나 이미지 정보가 전부 불러와지기 전, UI 사이즈의 영향을 주는 것을 방지해 줍니다.
•
Faster Page Loads (viewport 진입 시 로드 / blur 처리)
•
Asset Flexibility (리사이징)
•
Next에서 제공하는 Image 태그
º src 요소에 직접 path를 넣는 것이 아닌 public 경로에 이미지를 import 해서 사용합니다.
•
lazy loading 기능이 기본적으로 포함됩니다.
3.
Next.js 의 Data Fetching
3-1. CSR(Client Side Rendering)
담당 함수는 따로 존재하지 않고 리액트에서 사용하던 방법과 동일하게 사용하면 됩니다.
Client Console
3-2. SSR(Server Side Rendering)
getServerSideProps 함수 활용할 수 있습니다.
•
getServerSideProps 함수에 props를 return 해주면 SSR 방식으로 렌더링이 가능합니다.
Server Console
3-3. SSG(Static-Site Generation)
정적인 사이트 데이터를 가져와서 화면에 그려주는 방식으로 getStaticProps, getStaticPaths 함수를 활용합니다.
•
SSG는 개발 환경에서 SSR처럼 동작하기 때문에 Server Console에 나타나게 됩니다.
•
제대로 확인하기 위해서 build를 해야 합니다.
Server Console
•
build를 한 결과 Client Console, Server Console 그 어디에도 기록이 남지 않았습니다.
º build를 할 때 이미 페이지를 정적으로 만들어버린 것입니다.
•
정적인 페이지 한정이지만 SSR이 새로고침할 때마다 서버에 과부하를 주는 것을 막아줄 때 유용합니다.
•
getStaticPaths 함수는 getStaticProps 함수가 미리 그려야 할 path를 지정해 줍니다.
º getStaticPaths 함수는 무조건 getStaticProps 함수를 같이 사용해야 합니다.
3-4. ISR (Incremental Static Regeneration)
특정 주기로 데이터를 가져와서 다시 화면에 그려주는 기능입니다. getStaticProps 함수를 사용하는 것은 SSG와 똑같지만 revalidate를 return 해야합니다.
•
revaildate로 설정한 시간마다 데이터 fetching을 반복하게 됩니다.
º 특정 시간마다 새로운 값을 불러와야 할 경우 사용하면 SSR과 SSG의 장점을 합쳐 사용할 수 있게 됩니다.
4.
Router 이동하기
•
Next.js에서 지원하는 Link 태그 사용
•
함수로 이동
5.
Routing
React에서는 router을 사용하기 위해 react-router-dom 라이브러리를 설치해야 했습니다.
Next.js에서는 File-system 기반으로 pages 폴더 내에 있는 page 자체를 URL과 일대일 mapping 시켜 router의 기능을 수행하도록 해줍니다.
폴더가 여러 개 있는 경우 모든 폴더를 반영해 URL을 생성합니다.
ex) pages/product/first/second => /product/first/second
단, first에 index 파일이 없는 경우 /product/first에는 접근할 수 없습니다.
pages에 있는 index.js
•
pages에 있는 index.js가 우선 순위를 가져 화면에 보여졌습니다.
•
이때, src/pages에 있는 링크를 클릭하게 되면 404 에러가 뜨며 무시되는 것을 볼 수 있습니다.
6.
Dynamic Routes
6-1. Slug
slug로 정의해둔 파일 주소는 아무 값이나 입력해도 URL로 이동이 가능합니다.
ex) pages/category/[slug].js => /category/food, /category/shirt, /category/animal
pages/[username]/info.js => /ndc/info, neb/info, nea/info
Plain Text
복사
6-2. [slug] 값의 활용
하나의 페이지에서 여러 카테고리를 관리할 수 있습니다.
•
URL 주소의 파라미터는 useRouter Hook의 query를 사용해 추출합니다.
º 이때 파라미터의 값은 문자열로 들어오게 됩니다.
•
URL에서 다른 query를 추가해 여러 값을 받을 수 있습니다.
º ex) category/sports?from=event URL이 있다면
º {“slug”: “sports”, “from”: “event”}의 형식으로 받아집니다.
6-3. 다중 슬러그
pages/[username]/[info].js
•
• ex) jimmi/height URL이 있다면
6-4. 옵셔널 슬러그
•
pages/cart/[…slug].js => /cart로 접근하면 404 에러 발생합니다.
•
pages/cart/[[…slug]].js로 하면 slug가 존재하지 않아도 에러가 발생하지 않습니다.
7.
Shallow Routing
getServerSideProps, getStaticProps 함수를 다시 실행시키지 않고, 현재 상태에서 URL만 바꾸는 방법입니다.
URL을 바꾸는 3가지 방식
원본 상태
7-1. location.replace(“url”)
•
클릭한 직후 clicked state가 true로 바뀌나 바로 false로 상태가 변경되었습니다.
º URL을 바꾸기 위해 페이지를 re-rendering 했기 때문입니다.
7-2. location.push(“url”)
•
clicked state가 true로 유지되는 것을 볼 수 있습니다.
º 로컬의 상태는 유지되는 반면, server가 한 번 호출되게 됩니다.
Server Console
7-3. router.push(“url”, undefined, { shallow: true })
•
clicked state가 true로 유지되며 server는 반응하지 않습니다.
◦
단, 다른 path로 바꿀 경우 유지가 되지 않습니다.
•
router.push의 옵션 중 하나인 as는 브라우저 URL 바에 표시되는 값을 말합니다.
Server Console
8.
API Routes
간단하게 프론트엔드 기능과 더불어 백엔드 코드를 구축할 수 있게 하는 기능입니다.
api 파일을 생성해 코드를 구현하고 원하는 곳에서 간단하게 불러올 수 있습니다.
결론
제가 생각한 Next.js에 대한 개인적인 의견들입니다. 해당 리서치를 진행하며 React와 비교해 어떤 것을 느꼈는지 정리해 보았습니다.
1. 개발자의 선택권을 늘려준다.
CSR만 주로 구현하는 React만 사용했을 때보다 CSR, SSR, SSG, 추가적으로 ISG까지 Next.js를 선택했을 때 렌더링 방식에 대한 개발자의 선택권이 늘어난다. 선택권의 증가로 페이지마다 렌더링 방식에 차이를 줄 수 있고 성능 향상도 기대해 볼 수 있다.
2. 파일 구조의 복잡성이 우려된다.
component 별로 구분해 파일을 분리하던 React와는 달리 모든 router 페이지를 pages에서 관리해야 하기 때문에 파일을 구분하는데 직관적으로 눈에 보이지 않을 확률이 높다. Next.js 13 버전에서는 pages, layouts, api를 app 폴더에서 제어하기 때문에 불편함이 더 증대될 수 있다.
3. 한 프로그램 내에서 프론트엔드와 백엔드 개발이 가능해진다.
프론트엔드 파트는 물론 간단한 api를 직접 만들어 사용할 수 있기 때문에 간단한 백엔드 개발이 가능해졌고 복잡성이 낮은 프로젝트는 Next.js 만으로 구현이 가능하다고 생각한다.
4. 불필요한 라이브러리 사용을 줄여준다.
Next.js 자체에서 제공하는 기능을 활용하면 불필요한 라이브러리 사용을 줄일 수 있다. 라우터 연결의 경우 파일과 URL이 일대일 매칭되기 때문에 React-Router-Dom과 같은 라이브러리 설치를 하지 않아도 되고 이미지 최적화 또한 Next.js 자체 기능을 사용해 할 수 있다.
본 기술블로그에 게재되는 모든 컨텐츠의 저작권은 케이티넥스알(kt NexR)에서 가지고 있으며, 동의 없는 컨텐츠 수정 및 무단 복제는 금하고 있습니다. 컨텐츠(글/사진/영상 등)를 공유하실 경우 반드시 출처를 밝혀주시기 바랍니다. Copyright(c) kt NexR, Inc. All Rights Reserved. |