[Next.js] 공유 미리보기 오류 (CSR, SSR)

김기영·2022년 3월 17일
0

NextJS

목록 보기
1/1
post-thumbnail

Next.js로 작업하던 프로젝트가 거의 마무리되어서 카카오톡 공유 기능을 추가하고 테스트를 해보았다.


분명 og tag를 제대로 입력해주었는데도 오류가 났고, 카카오톡 공유 뿐만 아니라 url을 복사해서 sns나 페이지에 붙여넣어도 미리보기가 없다고 나왔다. 며칠 동안 헤매다 결국 해결했는데 오류의 원인과 해결과정을 간단하게 알아보자.

구현

1. OGTEST 프로젝트 세팅

터미널에 다음 명령어를 순서대로 입력한다.

yarn create next-app OGTEST
cd OGTEST
yarn add axios swr

VS code로 OGTEST를 열고 루트 디렉토리에 src 폴더를 만든 후 pages 폴더를 src 안으로 이동시키자. styles 폴더와 pages안에 api 폴더는 필요없으니 삭제한다. 그러면 다음과 같은 폴더구조를 가지게 된다. 이것으로 기본 세팅 완료.

2. meta og tag 추가

미리보기 기능을 위해서는 다음의 태그를 추가해주어야 한다.

출처 : https://dev-jwblog.tistory.com/48

테스트를 위한 프로젝트이므로 간단하게 description 한 줄만 추가해보자. index.js 파일을 열어서 다음과 같이 수정한다.

import Head from "next/head";

export default function Home() {
  return (
    <div>
      <Head>
        <title>OG test</title>
        <meta property="og:description" content="OG tag 테스트 페이지 입니다." />
      </Head>
    </div>
  );
}

이후 yarn dev로 서버를 켜서 localhost:3000으로 접속하면 빈 페이지가 보인다. 개발자 도구에서 head를 확인해보면 넣어준 meta tag가 제대로 들어가 있음을 확인할 수 있다.

이제 og 태그 안의 content를 하드코딩이 아닌, 데이터를 받아서 동적으로 변경해보자.

3. swr로 데이터 받아오기

위에서 axios와 swr을 설치했었다. axios는 fetch함수를 쉽게 사용할 수 있도록 하는 라이브러리이며 swr은 Next.js에서 만든 React Hook 라이브러리이다. 이를 활용해서 데이터를 받아와보자.

import Head from "next/head";
import useSWR from "swr";
import axios from "axios";

const API_ENDPOINT = "https://api.sampleapis.com/futurama/info";

const fetcher = (url) => axios.get(url).then((res) => res.data);

export default function Home() {
  const { data, error } = useSWR(API_ENDPOINT, fetcher);
  if (error) return <div>error occurred</div>;
  if (!data) return <div>loading...</div>;
  console.log(data);
  return (...);
}

api는 futurama sample api를 사용했다. 데이터를 받아오는 동안 에러가 발생하면 에러 발생 문구를, 데이터를 아직 로딩중이면 로딩중이라는 문구를 나타낸다. 받아온 데이터는 다음과 같다.

이제 받아온 데이터를 활용해서 meta tag를 수정해보자.

4. 동적 meta og tag 적용

메타 태그의 content를 다음과 같이 수정해보자

  return (
    <div>
      <Head>
        <title>OG test</title>
        <meta property="og:description" content={data[0].synopsis} />
      </Head>
    </div>
  )


받아온 데이터가 잘 들어가있는 것을 확인할 수 있다. 그러면 뭐가 문제인가? 이대로 공유하면 잘 되지 않나? 할 수 있는데 아니다.

오류

1. 미리보기 테스트

우리는 지금 로컬에서 작업하고 있으므로 카카오 공유로 미리보기 테스트가 불가능하다. 배포한다면 물론 가능하지만 테스트 프로젝트이므로 배포하는 방법 보다는 다른 방법으로 테스트해보자.

터미널 혹은 윈도우 Git bash를 켜서 다음 명령어를 입력한다.

curl -v -X GET "http://localhost:3000"

curl은 웹 요청 linux 명령어 이며, -v 는 디버깅을 위해 요청과 응답 헤더까지 모두 표시해달라는 옵션이다. -X는 요청을 보내는 method를 직접 지정해주는 옵션이며 우리는 GET으로 페이지 데이터를 받아올 것이다.

해당 명령어를 입력하면 뭐가 많이 출력될텐데 우리가 확인해야할 부분은 아래쪽에 나온 HTML 부분이다.

postman으로 더 깔끔하게 확인할 수도 있다.

이상하지 않은가? 추가해둔 og:description 태그가 사라지고 meta tag count 값이 2로 나타났다. 분명히 웹 상에서는 og:description 태그를 포함해서 총 3개인데 왜이럴까? 다른 코드를 그대로 두고 메타 태그만 아까 잘 나오던 <meta property="og:description" content="OG tag 테스트 페이지 입니다." /> 로 바꿔보아도 테스트 결과는 같다.

2. 원인

이 오류를 해결하기 위해서는 브라우저의 렌더링 과정과 방식을 이해해야한다. 브라우저의 렌더링 과정은 일단 넘어가고, 렌더링 방식에는 어떤 것이 있는지 알아보자. 렌더링 과정에 대한 자세한 설명은 나중에 포스팅해서 연결하겠다.

렌더링 방식이란 HTML을 어디서 만들 것인가?에 따라 CSR, SSR, SSG로 나뉜다.

CSR (Client Side Rendering, SPA)

말 그래도 client에서 HTML을 만든다. 과정은 다음과 같다.

[ 클라이언트 ] → [ 정적 서버 ] → [ 정적 서버 : 빈 HTML과 JS파일을 내려줌 ] → [ 클라이언트 : DOM을 생성 ]

HTML은 빈 상태로 시작하여 JS 파일을 불러오면 JS가 DOM을 생성해서 화면에 뿌려주는 식이다. Angular, React, Vue, Svelte, 기타 등등 대부분의 SPA 프레임워크, 라이브러리가 여기에 해당한다. 물론 해당 프레임워크, 라이브러리에서도 렌더링 방식을 바꿀 수 있지만 기본적으론 CSR이다.

  • 장점: 화면 전환 시 깜빡임이 없다.
  • 단점: 초기 렌더링이 느리다.

SSR (Server Side Rendering)

서버에서 HTML을 다 만들어서 client로 내려준다. 과정은 다음과 같다.

[ 클라이언트 ] → [ 렌더링 서버 ] → [ 렌더링 서버: HTML을 생성 ] → [ 클라이언트 ]

웹의 시작부터 현재까지 쭉 쓰이고 있는 렌더링 방식이며, JSP (Java), PHP, ASP, Handlebars (Node) 등 서버 사이드 렌더링을 지원하는 언어는 아주 다양하다. 프론트엔드 개발자가 해당 언어를 배워서 SSR 한다..? 물론 할 수 있다. 하지만 JS하기도 바쁜데 굳이...? 해서 나온게 Next.js 다. Next.js는 리액트를 기반으로 SSR, SSG를 할 수 있게 만든 프레임워크이다.

  • 장점: 렌더링 속도가 빠르다.
  • 단점: 화면 전환 시 깜빡임이 있다.

SSG (Static Site Generation)

빌드 시점에 데이터랑 JS를 합쳐서 HTML을 만든다. 과정은 다음과 같다.

[ 클라이언트 ] → [ 정적 서버 ] → [ 정적 서버 : 이미 생성되어있던 HTML을 내려줌 ] → [ 클라이언트 ]

빌드 될 때 이미 HTML 파일이 다 생성되어있다. 즉 서버에서 생성하지 않고, 클라이언트에서는 렌더링만 한다. 대표적인 프레임워크, 라이브러리로는 NextJS, Gatsby, Remix 등이 있다.

그래서 오류의 원인은 무엇인가?

바로 CSR 이기 때문이다. 엥? 아까 Next.js는 SSR 이라면서요? 이를 이해하기 위해서는 다시 Next.js의 작동 방식을 이해해야한다.

Next.js의 작동 방식, Hydrate

클라이언트가 웹 페이지에 접속하면 Server 에서 미리 웹 페이지를 Pre-Rendering 한다. 그리고 Pre-Redering으로 인해 생성된 HTML document를 클라이언트에게 전송한다. 이 때, HTML document는 단순히 웹 화면만 보여주는 HTML이며, 자바스크립트 요소들이 하나도 없다.

이후 번들링 된 자바스크립트 코드들을 클라이언트에게 전송한다. 이 자바스크립트 코드들이 클라이언트에서 이전에 보내진 HTML DOM 요소 위에서 한번 더 렌더링 된다. 자바스크립트 코드들이 DOM 요소 위에 물을 채우 듯 필요로 하던 요소들을 채운다 하여 Hydrate(수화)라는 용어를 쓴다.


즉 초기렌더링은 SSR이며, 이후에 CSR로 동작한다는 의미이다.

데이터 fetching

우리는 앞에서 데이터를 받아올 때, fetch함수를 쉽게 사용할 수 있는 axios와 Next.js에서 만든 React Hook 라이브러리 useSWR을 사용했다. 데이터를 받아오는 부분은 JS 파일에 해당하는데 SSR로 동작하는 초기렌더링에는 JS 파일을 포함하지 않는다. 따라서 앞서 작성한 페이지에서 axios, useSWR 등을 사용하는 순간부터는 CSR의 영역이다.

해결방법

getServerSideProps

Next.js는 SSR, SSG를 쉽게 할 수 있는 리액트 기반의 프레임워크라고 했다. 데이터 fetch 부분을 getServerSideProps를 사용해서 SSR로 바꿔보자. index.js 파일을 다음과 같이 수정한다.

import Head from "next/head";
import axios from "axios";

const API_ENDPOINT = "https://api.sampleapis.com/futurama/info";

export default function Home({ data }) {
  return (
    <div>
      <Head>
        <title>OG test</title>
        <meta property="og:description" content={data[0].synopsis} />
      </Head>
    </div>
  );
}

export const getServerSideProps = async (context) => {
  const res = await axios.get(API_ENDPOINT);
  const data = res.data;
  console.log(data);
  return {
    props: {
      data,
    },
  };
};

getServerSideProps 메서드 안에서 데이터를 받아오고, 받아온 데이터를 props로 페이지에 넘겨주었다. console.log(data)는 웹페이지의 콘솔이 아닌, VS Code의 터미널에서 확인할 수 있다.

이로써 SSR이 잘 된 것은 확인했다. 이제 우리의 최종 목표인, meta og tag가 잘 들어있는지 테스트 해보자.

미리보기 테스트

위에서 사용했던 방법을 그대로 적용하면 된다. 터미널 curl이나, postman으로 확인해보자.

해결 완료.

회고

이 오류 해결하려고 5일 동안 고민했으며 구글링, stackoverflow 등 안찾아본 곳이 없다. next-seo 도 추가해보고, _document.tsx, _app.tsx 를 수정해보고 카카오 데브톡에 질문도 남겼었고 나름 친분있는 개발자 분께 물어보기도 했다. 받았던 두 답변 모두 간단히 말하면 SSR이 제대로 동작하는지 체크해라 였다. 분명히 getServerSideProps로 SSR이 잘 동작하는 것 같은데 왜 안나오나 의문이었는데, 해결책은 의외로 간단했다.

페이지에서 useSWR을 사용하고 있었는데 이를 주석처리 안한 채 getServerSideProps를 추가했기 때문이었다....

왜 그랬니..

당시 curl이나 postman으로 로컬 서버도 테스트가 된다는 것을 모르고, pr 올린 후 CI/CD 된 pr preview 사이트에서 url 공유 하면서 확인했었다.

머리가 나쁘면 몸이 고생한다고, 저 위로 30개는 더있다.....

그런데 해결하기 몇 시간 전, 깃헙 레포지토리 토큰 이슈가 발생해서 CI/CD가 제대로 진행되지 않았고, pr을 올리면 바로 Credential error가 발생했었다.

나... pr preview로 테스트해야되는데... pr이 에러 나네...

해서 찾아낸 방법이 터미널의 curl이다. curl로 로컬서버 테스트 하던 도중, 필수 코드(우리가 위에서 작성한 코드)를 제외하고 전부 주석처리 하니 해결되는 것을 확인할 수 있었다. 어떤것이 문제인가 주석처리된 것을 하나하나 없애다 보니 useSWR이 문제였다.

해결은 했지만 useSWR을 쓰고 meta tag에 하드코딩한 것은 왜 적용이 안되나? 는 아직도 의문이다. useSWR을 쓰는 페이지는 hydrate로 동작하는 것이 아니고 전체가 CSR 인 것인가? 아니면 hydrate로 동작할 때 meta tag만 못가져오는 것인가?

Next.js 더 공부 하자..

참고

https://devtalk.kakao.com/t/scrap-url/24950
https://nextjs.org/docs/basic-features/data-fetching/client-side
https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props
https://helloinyong.tistory.com/315

profile
FE Developer

0개의 댓글