DevOps/Optimization

SPA 프로젝트에서 SEO 개선하기

닝닝깅 2024. 5. 14. 17:07

📌 개선 전 SEO

SPA는 하나의 웹 페이지에서 동적으로 컨텐츠를 업데이트 된다.

이때 컨텐츠는 클라이언트에서 렌더링 되기 때문에 크롤러가 컨텐츠를 제대로 인식하지 못해 SEO 문제가 발생한다.

next.js 프레임워크로 SSR을 사용하여 개선할 수 있지만, 이번 프로젝트는 next를 사용하는 프로젝트가 아닌 관계로 별도의 세팅으로 SEO를 개선해볼 생각이다.

 

 

📌 개선 방법

1 ) robots.txt과 sitemap.xml 생성

검색엔진 크롤러가 사이트 구조를 이해하고 정확하게 인덱싱 할 수 있도록 하기 위해 robots.txt와 sitemap.xml 파일을 생성해야한다.

 

robots.txt

- 검색 엔진 크롤러에게 크롤링 할 수 있는 페이지에 대해 알려준다.

- 개인 정보가 포함된 페이지는 크롤링 하지 않도록 설정할 수 있다.

//예시
User-agent: *
Disallow: /private/
Disallow: /tmp/
Allow: /public/
Sitemap: https://example.com/sitemap.xml

 

sitemap.xml

- 웹사이트의 페이지 구조를 담고 있다.

- 모든 페이지의 url을 나열하여 기본적인 크롤러가 찾지 못하는 페이지도 찾을 수 있게도와준다.

 

나는 웹사이트 컨텐츠가 자주 변경되는 경우가 아니었기에 일단 xml-sitemaps 사이트에서 수동으로 사이트맵 파일을 만들어 추가시켜주었다. 추후 사이트에 변경사항이 빈번하게 생긴다면 react-router-sitemap 라이브러리를 통해 자동 생성하도록 수정할 생각을 하고 있다.

 

두 파일의 위치는 프로젝트 루트에 두면 된다. 나는 vercel을 사용하여 호스팅 서비스에 배포하였기 때문에 프로젝트 루트인 public 폴더 하위에 위치시켰다.

 

2) 동적인 메타태그 추가

메타태그는 웹 페이지의 정보를 설명하는 메타 데이터를 정의하기 위해 사용된다. 

 

spa는 하나의 html에서 모든 페이지가 관리되기 때문에 페이지별 메타태그를 적용하기 위해서는 메타태그를 동적으로 제어할 수 있는 기능이 필요하다.

 

이 기능을 구현하기 위해 react-helmet을 사용했다.

사용방법은 간단하다. Helmet 태그 하위에 메타태그를 추가하면 된다.

<Helmet>
  <title>페이지 제목</title>
  <meta name="description" content="페이지 설명" />
  <meta name="keywords" content="키워드1, 키워드2, 키워드3" />
</Helmet>

 

🚨 이슈 발견!

크롤러 접근이 허용된 페이지에만 동적인 메타태그 설정을 해주었더니 접근이 허용되지 않은 페이지로 넘어갔을 때 기존 메타태그가 그대로 유지되는 이슈를 발견했다.

 

시도 1)

처음에는 useEffect의 cleanup 함수를 통해서 언마운트될 때 메타태그를 초기화 시킬 수 있도록 설계하였으나, 언마운트 되기 전 초기화부터되는 예상과는 다른 동작을 확인하였고, 다른 방법을 찾아보았다.

 

시도 2)

결국 메타태그를 다루는 컴포넌트를 별도로 만들고 페이지 레이아웃 컴포넌트에 추가시켜 모든 페이지에 적용되도록 하여 이슈를 해결했다. page props가 존재하지 않는 경우는 접근이 허용되지 않은 페이지로 메타태그가 초기화된다.

import { Helmet } from "react-helmet-async";

const Meta = ({ page, product }: IMeta) => {
  if (!page) {
    return (
      <Helmet>
        <title>BYHAND</title>
      </Helmet>
    );
  }

  const title = {
    home: "홈",
    products: "전체상품",
    detail: "상품정보",
  }[page];
  const description = {
    home: "홈입니다",
    products: "전체상품입니다",
    detail: `${product?.productName}`,
  }[page];
  const url = {
    home: "https:",
    products: "https:",
    detail: `https:`,
  }[page];

  return (
    <Helmet>
      <title>{title}</title>
      <meta name="description" content={description} />
      <meta property="og:type" content="website" />
      <meta property="og:url" content={url} />
      <meta name="og:title" content={title} />
      <meta name="og:description" content={description} />
    </Helmet>
  );
};

export default Meta;

 

+) 이미지 alt 옵션 추가

이미지 대체텍스트 추가 깜박했다가 알게된 사실..!

검색엔진 크롤러가 이미지를 이해하는데에는 제한이 있기 때문에 더 효율적인 인덱싱을 대체 텍스트로 이미지 내용을 설명해주어야 한다.  대체텍스트는 웹 접근성 향상에도 기초적인 부분이니 항상 잊지 말도록 하자

 

 

📌 개선 후 SEO

Lighthouse 기준으로 SEO 점수 만점! 받았다!