xtring.dev

[Next.js] Next.js 공식문서 파헤치기(2) - 기본개념 "Pages, Pre-Rendering 방식(SSG/SSR)" 본문

Front-End/Next.js

[Next.js] Next.js 공식문서 파헤치기(2) - 기본개념 "Pages, Pre-Rendering 방식(SSG/SSR)"

xtring 2021. 7. 29. 19:30

 

 

 

 

Next.js에는 몇가지 강력한 특징이 있습니다.(아래) 이번 아티클에서는 SSG와 SSR에 대한 내용을 설명드리겠습니다🤓

 

 

 

 

 

  Next.js의 Pages

  Next.js에서 page는 pages 디렉터리의 .js, .jsx, .ts, .tsx 파일로부터 export된 React Component입니다. 각 페이지는 그들의 파일 이름을 기반으로 route됩니다.

 

  예를 들어, 만약 pages/about.js 파일을 생성한다면 /page로 쉽게 접근가능합니다.

function About() {
    return <div>About</div>;
}

export default About;

이렇게 About은 하나의 페이지로서 사용됩니다.

 

 

 

 

 

  Pre-rendering; 사전 렌더링

  기본적으로, Next.js는 모든 페이지를 pre-rendering합니다. 이는 Next.js가 Client-side의 JavaScript에 의해 실행하는 것 대신에 사전에 각 페이지의 HTML을 생성하는 것을 의미합니다.(pre-render) 그리고 이러한 pre-rendering 방식은 더 나은 성능과 SEO을 가능하게 합니다.

 

  각각 생성된 HTML은 그 페이지를 위한 최소한의 JavaScript code로만 이루어집니다. 브라우저에서 하나의 페이지가 로드될 때 그 페이지의 JavaScript code가 실행(로드)되고 페이지를 반응(interacitve)성 있게 만듭니다.(이러한 과정을 hydration(수분 공급)이라고 합니다.)

 

 

 

 

 

  Pre-rendering의 두가지 방식

  Next.js는 Static GenerationServer-side Rendering이라는 두가지 방식의 pre-rendering 방식을 가지고 있습니다. 이 둘의 가장 큰 차이점으로 페이지의 HTML이 생성되는 방식에서 차이가 있습니다.(지금은 잘 이해가 되지 않을 수 있지만 이 아티클을 끝까지 보신다면 이해할 수 있습니다!)

 

  • Static Generation : HTML은 build-time에 생성되며 모든 요청에서 미리 생성된 HTML을 재사용(Next.js's recommand)
  • Server-side Rendering : HTML은 각각의 요청마다 생성. 즉, 재사용은 하지 않음

 

  중요하게도, Next.js는 각 페이지에 당신이 사용하고자 하는 pre-rendering 방식을 선택할 수 있게 해줍니다. 또한 더 나아가 대부분의 페이지에서는 Static Generation을 사용하고 다른 페이지에서는 Server-side Rendering을 이용하여 "Hybrid" Next.js 앱을 만들 수 있게 해줍니다.

 

  Next.js에서는 성능상의 이유로 Server-side Rendering 방식보다 Static Generation 방식을 사용하는 것을 추천합니다. Static Generation 페이지는 성능 향상을 위한 추가 구성없이 CDN에서 캐싱을 합니다.(이를 통해 미리 생성해 놓은 HTML을 다시 재사용 할 수 있습니다.) 그러나 페이지에 최신의 데이터를 유지해야하는 경우 Server-side Rendering이 유일한 선택일 수 있습니다. 또한 Next.js는 Client-side Rendering 방식도 지원합니다...! 이 방식은 페이지 일부를 클라이언트 측에서 JavaScript를 실행시킨다는 말입니다.

 

 

 

 

 

  Static Generation

Static Generation을 사용한다면, 페이지의 HTML은 build-time(빌드 시점)에 생성됩니다.즉, production에 페이지의 HTML은 'next build'가 실행되는 시점에 생성된다는 말입니다. 생성된 HTML은 각각의 모든 요청(request)에서 재사용될 것입니다. 그리고 CDN에 의해 캐싱될 수 있습니다.

 

  생성되는 페이지에서 데이터를 포함하냐 안 하냐에 따라 Static Generation을 사용할때 조금 다릅니다. 이유는 build-time에서 미리 HTML을 생성하기 때문이겠죠? 아래에서 외부 데이터를 가져오는 경우와 아닌경우를 살펴봅시다.

 

 

Static Generation without data

function About() {
    return <div>About</div>
}

위 코드에서는 pre-render과 함께 데이터를 가져오지 않습니다. 이러한 경우 build-time에 page의 HTML생성합니다.

 

 

Static Generation with data

  때때로 pre-rendering을 위해 외부 데이터를 가져와야하는 경우가 있습니다. 두 가지 시나리오가 있으며 하나 또는 둘 다 적용될 수 있습니다. 각각의 경우에 Next.js가 제공하는 다음 기능을 사용할 수 있습니다.

 

(1) 당신의 page contents가 외부 데이터에 의존하는 경우 ⇒ getStaticProps

(2) 당신의 page path가 외부 데이터에 의존하는 경우 ⇒ getStaticPaths(일반적으로 getStaticProps 와 함께 사용)

 

시나리오 1) 페이지의 contents가 외부 데이터에 따라 다른 경우
당신의 blog page는 CMS(Content Management System)으로부터 blog post 리스트를 가져와야 한다.

// TODO: pre-render가 이루어지기 전에 API을 통해 post를 가져와야 한다.
function Blog({ posts}) {
    return (
        <ul>
            {posts.map((post) => (
                <li>{post.title}</li>
            ))}
        </ul>
    )
}

 

  데이터를 가져와 pre-render하기 위해서, Next.js를 사용하면 해당 파일에서 getStaticProps함수를 비동기 방식으로 export하여 사용합니다. 이 함수는 build-time 시 호출되며 pre-rendering 시 가져온 데이터를 page의 contents로 전달할 수 있습니다.

 

function Blog({ posts }) {
    // Render posts...
}

// build-time 시 실행
export async function getStaticProps() {
    const res = await fetch('https://.../posts');
    const posts = await res.json();

    return {
        porps: {
            posts,
        }
    }
}

export default Blog;

 

 

시나리오 2) 페이지의 경로가 외부 데이터에 따라 다른 경우
Next.js는 Dynamic Routing을 통해 페이지를 생성합니다. 예를 들어, pages/posts/[id].js 파일을 생성합니다. 'id' 기반의 단일 블로그 포스트를 보여주기 위해서 posts/1을 액세스할 때 id: 1인 블로그 포스트를 볼 수 있습니다.

 

  id 값은 pre-rendering 시 외부 데이터에 따라 달라질 수 있습니다. 이것을 다루기 위해서 동적 페이지(pages/posts/[id].js)로 부터 getStaticPaths 함수를 비동기 방식으로 사용합니다. 이 함수는 build-time에 실행되며 pre-rendering을 위해 원하는 path를 구체화합니다.

 

export async function getStaticPaths() {
    const res = await fetch('https://.../posts');
    const posts = await res.json();

    const paths = posts.map((post) => ({
        params: { id: post.id },
    }));

    // { fallback: false }는 다른 (예외 케이스의) 라우팅 시 404를 발생한다는 의미
    return {  paths, fallback: false }
}

 

그리고, pages/posts/[id].js에서 getStaticProps를 export 하게되면 id를 가진 게시물에 대한 데이터를 가져와 페이지를 pre-render하는데 사용할 수 있습니다.

 

function Post({ post }) {
  // Render post...
}

export async function getStaticPaths() {
  // ...
}

export async function getStaticProps({ params }) {
  const res = await fetch(`https://.../posts/${params.id}`)
  const post = await res.json()

  return { props: { post } }
}

export default Post

 

 

 

 

언제 Static Generation을 사용해야 할까?

  Next.js 공식 문서에서는 Static Generation(with or without data)을 사용하는 것을 가능한 권장합니다. 왜냐하면, build-time에 생성된 HTML을 CDN 캐시를 통해 제공하기 때문에 각 요청에 따라 Server-side rendering 하므로 더 빠른 성능을 보여줄 수 있기 때문입니다. 예를 들어 아래 페이지들에서 사용합니다.

 

  • Marketing pages
  • Blog posts
  • E-commerce product listing
  • Help and documentation

 

  스스로에게 "사용자의 요청에 앞서 이 페이지를 pre-rendering해도 되는가?"를 물어보세요. 대답이 "예"라면 Static Generation을 사용하면 됩니다.

 

  반면, Static Generation은 사용자가 요청하는 데이터를 보여줘야하는 경우엔 적합하지 않습니다. 페이지에 따라 데이터가 자주 업데이트 되는 경우 매 순간 페이지의 contents가 변경될 수 있기 때문입니다. 아래의 경우를 살펴봅시다.

 

(1) Client-side Rendering과 함께 Static Generation을 사용하는 경우

페이지의 일부를 pre-rendering하지 않고 Client-side에서 JavaScript를 실행항여 contents를 채울 수 있습니다.

(2) Server-side Rendering을 하는 경우

페이지를 매번 서버에서 pre-rendering하면 CDN을 통한 캐싱이 의미가 없기 때문에 rendering 성능이 저하됩니다. 하지만 데이터와 contents는 항상 최신을 유지할 수 있습니다. 만약, 하나의 페이지에서 Server-side Rendering을 사용한다면, HTML 페이지는 매 순간 요청(request)에 의해서 생성된다는 말입니다.

 

 

 

 

 

  Server-side Rendering(SSR, Dynamic Rendering)

  만약 하나의 페이지에서 Server-side Rendering하게 되면, HTML 페이지는 모든 요청(request)에서 생성됩니다.

 

  하나의 페이지를 Server-side Rendering 하기 위해서, getServerSideProps 함수를 비동기 처리하여 사용합니다. 이 함수는 모든 요청(request)에서 Server에 의해 실행됩니다.

 

  예를 들어, 외부 API로 부터 자주 업데이트되는 데이터를 pre-rendering하기 위한 페이지가 필요하다면, 데이터를 가져오기 위한 getServerSideProps 함수를 작성할 수 있으며 아래 코드와 같이 페이지에 데이터를 전달할 수 있습니다.

 

function Page({ data }) {
  // Render data...
}

export async function getServerSideProps() {
  const res = await fetch(`https://.../data`);
  const data = await res.json();

  return { props: { data } };
}

export default Page;

 

  위 코드를 보면 getServerSidePropsgetStaticProps와 비슷합니다. 그러나, getServerSideProps는 build-time이 아닌 모든 요청(request) 마다 실행되는 차이점을 가집니다.

 

 

 

 

 

Ref. 

https://nextjs.org/docs/basic-features/pages#scenario-1-your-page-content-depends-on-external-data

 

Basic Features: Pages | Next.js

Next.js pages are React Components exported in a file in the pages directory. Learn how they work here.

nextjs.org

 

반응형

'Front-End > Next.js' 카테고리의 다른 글

[Next.js] Next.js 공식문서 파헤치기(1) - 시작하기  (0) 2021.07.22
Comments