WIL 20 ( Weeked I Learned ) - 23/07/09

용스·2023년 7월 9일
0

SEO에 관심이 많던 찰나 React 프로젝트에 SEO를 설정해 보기로 했다.

SEO란?

검색엔진 최적화, 즉 검색엔진에서 찾기 쉽도록 사이트를 개선하는 프로세스

구글 크롤러는 일정 시간이 지나면 스케줄러를 통해 모든 웹 사이트들의 내용을 긁어간다고 한다.

이때 SEO 설정이 잘 되어 있는 사이트들을 검색 결과에 노출 시켜준다고 하는데..

흠..

사실 어떻게 크롤링을 해가는지 이해가 되지 않는다.

meta description을 설정해두어도 사이트의 heading 태그를 description에 넣지 않나..

어떻게 설정해줘야 할지 막막하기만 하다.

( 네이버는 깔끔하게 잘 되던데.. ㅠㅠ)

이번에는 React 프로젝트에 og 태그를 설정했지만 결과적으로 실패었다.

웹 사이트 상에서는 og 태그가 개발자 도구에서 잘 나타나지만 카카오 sharing debugger나 facebook sharing debugger에 노출이 되지 않기 때문에 실패라고 단정지었다..

그 이유는 정적 빌드가 되지 않기 때문이라고 결론 내렸다.

시도해 본 방법

react-helmet을 통해 시도한 방법과 custom hook을 사용하여 시도하였다.

1. react helmet

페이지마다 SEO를 적용하기 위해 고민해 본 분이시라면 한번쯤 들어봤을 법한 패키지다.

react-helmet 설치

npm i react-helmet

코드 적용하기

/* SEO.tsx */
import React from "react";
import { Helmet } from "react-helmet";

interface SEOProps {
 title: string;
 url: string;
}

const SEO = ({ title, url }: SEOProps) => {
 return (
   <Helmet>
     <title>{title}</title>
     <meta property="og:title" content={title} />
     <meta property="og:url" content={url} />
   </Helmet>
 );
};

export default SEO;

/* PageA.tsx */
import React from "react";
import SEO from "../SEO";

const PageA = () => {
 return (
   <>
     <SEO title="pageA" url="https://your-domain/pageA" />
     <div>PageA</div>
   </>
 );
};

export default PageA;

/* PageB.tsx */
import React from "react";
import SEO from "../SEO";

const PageA = () => {
 return (
   <>
     <SEO title="pageB" url="https://your-domain/pageB" />
     <div>PageA</div>
   </>
 );
};

export default PageA;

/* App.tsx */
import React from "react";
import CustomRoute from "./pages/route";
import { useNavigate } from "react-router-dom";
import SEO from "./SEO";

function App() {
 const navigate = useNavigate();
 const handleOnClickButton = (path: string) => () => {
   navigate(path);
 };
 return (
   <>
     <SEO title="My Test App" url="https://test-74951.web.app" />
     <button onClick={handleOnClickButton("/pageA")}>Button A</button>
     <button onClick={handleOnClickButton("/pageB")}>Button B</button>
     <CustomRoute />
   </>
 );
}

export default App;

배포해서 확인하기

firebase를 통해 프로젝트를 배포하고 검사 탭에서 확인해보았다.


크롬, 파이어폭스, 사파리, 네이버 웨일, 마이크로소프트 엣지 모두 다 정상 동작하는 걸 확인했다.

카카오 sharing debugger로 확인하기

좋아.. 카카오도 동작하겠지?

아예 og 태그가 적용되지 않았다.

2. custom hook으로 만들기

직접 dom element를 수정해보도록 custom hook을 제작했다.

index.html 작성하기

<!-- index.html -->
<title>My Test App</title>
<meta property="og:title" content="My Test App" />
<meta property="og:url" content="https://your-domain/" />

index.htmltitle, og:title, og:url를 설정해 두었다.
이를 작성해두지 않으면 querySelector에서 해당 요소를 읽어올 수 없기 때문에 에러가 발생한다.

custom hook 만들기

/* useSetMetaTags.tsx */
import { useEffect } from "react";

const useSetMetaTags = (title: string, path: string) => {
  const setMetaTags = () => {
    if (!document.head) return;

    const titleElement = document.head.querySelector("title");
    const ogTitleElement = document.head.querySelector(
      'meta[property="og:title"]'
    );

    const ogUrlElement = document.head.querySelector('meta[property="og:url"]');

    if (titleElement !== null) {
      titleElement.textContent = title;
    }

    if (ogTitleElement !== null) {
      ogTitleElement.setAttribute("content", title);
    }

    if (ogUrlElement !== null) {
      ogUrlElement.setAttribute(
        "content",
        `https://your-domain/${path}`
      );
    }
  };

  const resetMetaTags = () => {
    if (!document.head) return;

    const titleElement = document.head.querySelector("title");
    const ogTitleElement = document.head.querySelector(
      'meta[property="og:title"]'
    );

    const ogUrlElement = document.head.querySelector('meta[property="og:url"]');

    if (titleElement !== null) {
      titleElement.textContent = "";
    }

    if (ogTitleElement !== null) {
      ogTitleElement.setAttribute("content", "");
    }

    if (ogUrlElement !== null) {
      ogUrlElement.setAttribute("content", "");
    }
  };

  useEffect(() => {
    setMetaTags();

    return () => resetMetaTags();
  }, []);
};

export default useSetMetaTags;

document.head를 읽지 못하면 fast return을 해주었고 null이 아닐 때 각 dom 요소를 설정할 수 있도록 하였다.

코드 적용

/* PageA.tsx */
import React from "react";
import useSetMetaTags from "../useSetMetaTags";

const PageA = () => {
  useSetMetaTags("PageA", "https://your-domain/pageA");
  return <div>PageA</div>;
};

export default PageA;

/* PageB.tsx */
import React from "react";
import useSetMetaTags from "../useSetMetaTags";

const PageA = () => {
  useSetMetaTags("PageA", "https://your-domain/pageB");
  return <div>PageA</div>;
};

export default PageA;

배포해서 확인하기

마찬가지로 모든 웹 사이트에서 동작한다.

카카오 sharing debugger로 테스트

순간 되는 줄 알았다..

확인해본 결과, 정적으로 작성 해놓은 index.html만 크롤링하고 있었다..

결론

meta 태그를 제대로 적용하기 위해서는 정적 빌드가 필요하다는 것을 알 수 있었다.

테스트 사항으로 gatsby를 사용하여 gatsby-plugin-helmet을 사용해 보는 방법..
( react-static도 있지만 2년 전부터 업데이트가 되지 않고 있는 듯 하다. )

제일 좋은 건 서버사이드 렌더링이 필요하다는 것이다.

참고

김정환님 블로그
react-static
react-helmet

profile
일단 해보자

0개의 댓글