올해부터 마음을 다잡기 위해 개인 블로그를 만드는 프로젝트를 하고 있었다.
기획 단계를 건너뛰고 개발부터 들어가다보니 별 생각없이 React + vite 환경으로 진행했는데
로고 사진과 manifest.json 등 홈페이지에서 필요한 것들을 구성하다 보니 SEO 관련 걱정을 하지 않을 수 없었다.

2022년 후반부 쯤 누군가에게 "Google의 검색 엔진에서 SPA도 SEO가 되는 것 같더라" 라는 말을 들었다.
그 당시 아무렇지 않게 일 잘하는 구글을 칭찬하고 넘어갔는데 문득 궁금해서 해당 내용을 찾아보기로 했다.
Google 검색 센터에서 해당 내용에 대한 힌트를 조금 얻을 수 있었는데 상위 빨간색 문구를 보고 Next.js로의 Migration을 결심하게 되었다.

NextJS 공식 홈페이지를 참고해서 Next.js 13버전으로 진행하려 했는데 예전에 Next를 사용했을 때와는 많이 다른 구조를 가지고 있는 것 같아서 기초부터 공부하고자 해당 글을 남기기로 했다.

Next.js

Next.js는 클라이언트가 웹 페이지를 요청하면 서버에서 미리 웹 페이지를 Pre-Rendering 하고 이에 대한 결과물인 HTML을 클라이언트에게 전송한다.
이후 번들링 된 리액트코드를 클라이언트에게 전송하며 클라이언트는 이를 받아 렌더링하며 Hydrate하게 된다.

하지만 웹 페이지를 Pre-Rendering 할 때 필요한 정보가 클라이언트에게 있거나 데이터 서버에서 받아와야 할 때 등 페이지 정보마다 다르게 진행해야 할 경우가 있다.
이를 위해 Next.js에선 Data-Fetching 기능을 내부에서 제공하게 되는데 자세히 보도록 하자.

getServerSideProps

  • 페이지 요청 시 다른 곳에서 데이터를 가져와 페이지를 렌더링해야 하는 경우에 사용한다.
  • 서버 측에서만 실행되고 브라우저에서는 실행되지 않는다.
  • pages 폴더에서 각 페이지 파일에서 독립 실행형 기능으로 내보내야한다.
    • _app, _document, _error에서 내보낼 수 없다

내가 이해한 해당 함수의 진행은 다음과 같다.

요청 후 실행되어서 반환되는 데이터 값을 사용해 렌더링하므로 각 사용자에 대한 데이터를 렌더링해야 할 때 사용할 수 있다.
하지만 매 요청마다 실행되는걸 기다리기 때문에 성능 저하를 걱정해야 한다.
기본적으로 CDN에 캐싱되지 않으며 캐싱 기능을 사용하려면 따로 설정해주어야 하는데
캐싱 기능을 적용하는 상황이라면 아래의 함수들을 고려해 볼 필요가 있다.

페이지에서
function Page({ data }) {
  return <>~~</>
}

// import type { GetServerSideProps, GetServerSidePropsContext, GetServerSidePropsResult } from "next";

// Function Type = GetServerSideProps
export async function getServerSideProps(context) {
  // Prop (context) Type = GetServerSidePropsContext
  const res = await fetch(`https://.../data`)
  const data = await res.json()
  
  // Return Type = GetServerSidePropsResult
  return { props: { data } }
}

export default Page

getStaticProps

  • 빌드 시에 함수가 실행되고 이를 반환한 데이터를 사용한다.
  • 한번 빌드 후 조작하지 않는다면 바뀌지 않는 데이터이다
  • 서버 측에서만 실행되고 브라우저에서는 실행되지 않는다.
  • pages 폴더에서 각 페이지 파일에서 독립 실행형 기능으로 내보내야한다.
    • _app, _document, _error에서 내보낼 수 없다
  • 개발 환경 (next dev)에서는 모든 요청에 대해 호출된다고 나와있다.

내가 이해한 해당 함수의 진행은 다음과 같다.

function Page({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}

// import type { GetStaticProps, GetStaticPropsContext, GetStaticPropsResult } from "next";

// Function Type = GetStaticProps
export async function getStaticProps(context) {
  // Prop Type = GetStaticPropsContext
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // Return Type = GetStaticPropsResult
  return {
    props: {
      data,
    },
  }
}

export default Blog

getStaticPaths

이 기능은 Pre-Render를 위한 기능이 아니라, Static Generation 을 위한 기능이다

  • getStaticProps와 비슷하게 빌드 시에 함수가 실행된다.
  • 페이지에서 동적 경로를 사용할 때 예상 가능한 path들에 대해 페이지를 미리 빌드하는 기능이다.
  • 경로를 지정해주기만 한다면 정적으로 사전 렌더링을 시작한다.
  • getServerSideProps와 함께 사용하지 못하며 getStaticProps와 사용해야 한다.

내가 이해한 해당 함수의 진행은 다음과 같다.

paths 값으로 빈 배열을 넘겨서 페이지 빌드를 연기할 수 있다고 한다.

// pages/posts/[id].js

// import { GetStaticPaths, GetStaticPathsContext, GetStaticPathsResult } from "next";
// Function Type = GetStaticProps
export async function getStaticPaths(context) {
  // Prop Type = GetStaticPathsContext
  // Return Type = GetStaticPathsResult
  return {
    paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
    fallback: false, // can also be true or 'blocking'
  }
}

export async function getStaticProps(context) {
  return {
    props: { post: {} },
  }
}

export default function Post({ post }) {
  return <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
}

모든 페이지에서 ?!

공식 홈페이지에 따르면 아래와 같은 말이 있다.

pages 폴더에서 각 페이지 파일에서 독립 실행형 기능으로 내보내야한다.
=> _app, _document, _error에서 내보낼 수 없다

Next.js 개발 중 모든 페이지에 대해서 getServerSideProps를 실행해야 할 경우 어떻게 해결해야 할까?

getInitialProps

Next.js의 예전 버전에서 이 getInitialProps 함수를 이용해서 컴포넌트에 필요한 Props를 해결해왔었다.
_app, _document, _error와 같은 페이지의 컴포넌트가 동작할 때 여전히 getInitialProps 함수가 있다면 실행되기 때문에 해당 함수를 지정해주어 모든 페이지에 대해서 실행할 수 있다.

Automatic Static Optimization

Next 9.3 이후 버전에서 getServerSideProps, getStaticProps, getStaticPaths등의 기능이 나왔는데, Next.js에서 getInitialProps보다 위 함수들을 사용하길 권고하는 이유가 있다.

이 기능들은 Automatic-Static-Optimization 기능을 지원해준다고 한다

If getServerSideProps or getInitialProps is present in a page, Next.js will switch to render the page on-demand, per-request (meaning Server-Side Rendering).
If the above is not the case, Next.js will statically optimize your page automatically by prerendering the page to static HTML.

요약하자면 getServerSideProps 혹은 getInitialProps가 각 페이지에서 사용되지 않을 경우 Next.js가 이를 최적화하기 위해 Static Generation 페이지를 생성하고 제공하게 된다는 의미이다.
더 자세한 내용에 대해선 공식문서에서 확인할 수 있다.

만약 개발하는 프로젝트 중 Static Generation 을 통한 서비스 제공이 중요하다고 생각된다면 전역에서 getInitialProps를 선언해주는 것을 고려해주는게 좋다.

참고

Next.JS - Data Fetching

0개의 댓글