Skip to content

💽 SEO : NextJS SSR 적용

김민형 edited this page Dec 10, 2022 · 1 revision

Knoticle 서비스에서 글을 작성할 수 있고 이를 블로그 형태로 확인해볼 수 있기에 SEO 성능이 높게 나오는 것이 중요하다. SEO 향상을 위해서 다양한 접근 방식을 가져갈 수 있지만 SSR을 적용하여 콘텐츠가 완성된 HTML 파일을 넘겨주는 방식으로 기존의 CSR 방식의 코드를 개선해보고자 한다.

CSR 방식의 현재 상황

// SSR 적용 전 코드

export default function Viewer() {
  const { data: article, execute: getArticle } = useFetch(getArticleApi);
  const { data: book, execute: getBook } = useFetch(getBookApi);
	...

  useEffect(() => {
    if (Array.isArray(router.query.data) && router.query.data?.length === 2) {
      const [bookId, articleId] = router.query.data;

      getBook(bookId);
      getArticle(articleId);
    }
  }, [router.query.data]);

  return (
    <>
      <GNB />
      {book && article ? (
        <Flex>
          {isOpened ? (
            <TOC book={book} articleId={article.id} handleSideBarOnClick={handleSideBarToggle} />
          ) : (
            <ClosedSideBar handleSideBarOnClick={handleSideBarToggle} />
          )}
          <ArticleContainer
            article={article}
            scraps={book.scraps}
            bookId={book.id}
            handleScrapBtnClick={handleModalOpen}
          />
        </Flex>
      ) : (
        <div>loading</div>
      )}
    </>
  );
}

위는 뷰어 페이지에서 useEffect를 사용해서 책과 글 각각에 대한 API 요청을 보내 값을 받아와 렌더링을 해주고 있다. 따라서 해당 페이지가 렌더링 된 이후에 부가적으로 useEffect의 콜백 함수로 요청을 보내는 형식이기 때문에 API 요청이 늦어지게 되면 loading으로 보이는 페이지가 잠시 화면에 떠있다가 데이터가 들어오면 해당 콘텐츠에 맞는 내용을 보여준다.

추가적으로 확인을 해보면 Chrom의 환경 설정에서 Disable JavaScript값을 적용한 뒤에 새로고침을 해보면 Client 단에서 데이터를 요청해서 받아온 값을 보여주는 로직이기 때문에 데이터가 표시되지 않는 것을 확인 해볼 수 있다.

CSR이 적용된 뷰어페이지

CSR이 적용된 뷰어페이지

Chrome / Settings에서 Disable Javascript를 활성화한 뒤의 뷰어페이지

Chrome / Settings에서 Disable Javascript를 활성화한 뒤의 뷰어페이지

해당 페이지의 소스를 확인해보게 되면 NextJS에서 빌드 타임에 SSG 방식으로 기본 레이아웃 HTML을 작성해서 보내주었기 때문에 Client 단에서 데이터 요청을 보내지 않고도 작성할 수 있는 컴포넌트들은 HTML 파일로 생성된 것을 확인 할 수 있다. 하지만 useEffect 내부에 있는 API요청 결과를 활요한 컴포넌트의 값은 채워지지 않을 것을 볼 수 있다.

페이지 소스

SSR 적용해보기

// SSR 적용 후 코드

export default function Viewer({ book, article }: ViewerProps) {
  
  return (
    <>
      <GNB />
      {book && article ? (
        <Flex>
          {isOpened ? (
            <TOC book={book} articleId={article.id} handleSideBarOnClick={handleSideBarToggle} />
          ) : (
            <ClosedSideBar handleSideBarOnClick={handleSideBarToggle} />
          )}
          <ArticleContainer
            article={article}
            scraps={book.scraps}
            bookId={book.id}
            handleScrapBtnClick={handleModalOpen}
          />
        </Flex>
      ) : (
        <div>loading</div>
      )}
    </>
  );
}

export const getServerSideProps: GetServerSideProps = async (context) => {
  const [bookId, articleId] = context.query.data as string[];
  const book = await getBookApi(bookId);
  const article = await getArticleApi(articleId);

  return { props: { book, article } };
};

NextJS 프레임워크에서 지정한 getServerSideProps 함수를 활용하면 해당 페이지를 요청받았을 때 서버에서 API요청을 보내 미리 데이터를 받아서 HTML을 작성할 때 해당 데이터를 채워주는 방식으로 동작한다. 동적 라우팅을 사용하여 url의 값을 활용해야 하는 경우에도 context를 사용해서 해당 값을 동적으로 받아서 처리해 줄 수 있다.

이처럼 SSR 방식을 적용해보면 Disable JavaScript값을 적용해도 서버 측에서 미리 데이터를 채워넣은 HTML 파일을 보내줘서 렌더링 하기 때문에 전혀 문제 없이 정상적으로 모든 데이터가 채워진 상태로 동작하는 것을 확인할 수 있다.

Disable Javascript를 활성화해도 뷰어페이지가 정상적으로 표시된다

Disable Javascript를 활성화해도 뷰어페이지가 정상적으로 표시된다

데이터가 다 채워진 HTML 파일 소스를 확인할 수 있다 .

데이터가 다 채워진 HTML 파일 소스를 확인할 수 있다 .

레퍼런스

Velog SSR

Next.js SSR with dynamic routes for rendering social media app profile pages?

Data Fetching: getServerSideProps | Next.js

Clone this wiki locally