Skip to content

SEO 최적화

subsub-e edited this page Aug 25, 2024 · 1 revision

1. meta 태그 추가

<meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta
      name="description"
      content="캐스퍼에 당첨될 수 있는 기회!! 이벤트 참여하고 캐스퍼 EV를 받아가세요!!"
    />
    <meta property="og:title" content="캐스퍼 이벤트" />
    <meta
      property="og:description"
      content="캐스퍼에 당첨될 수 있는 기회!! 이벤트 참여하고 캐스퍼 EV를 받아가세요!!"
    />
    <meta
      property="og:image"
      content="https://softeer4-team8.s3.ap-northeast-2.amazonaws.com/%E1%84%86%E1%85%B5%E1%84%82%E1%85%B5+%E1%84%8F%E1%85%B1%E1%84%8C%E1%85%B3+7.svg"
    />

a. <meta name="viewport" content="width=device-width, initial-scale=1.0" />

  • 역할: 이 메타 태그는 웹페이지가 다양한 디바이스에서 잘 표시되도록 화면의 크기를 조정한다.
  • SEO 효과: 검색 엔진은 반응형 디자인(모바일 친화적)을 선호한다. 이 태그는 모바일 디바이스에서 페이지가 올바르게 표시되도록 하여, 모바일 사용자 경험을 향상시키고, 모바일 검색 결과에서의 순위를 높이는 데 기여함.

b. <meta name="description" content="캐스퍼에 당첨될 수 있는 기회!! 이벤트 참여하고 캐스퍼 EV를 받아가세요!!" />

  • 역할: 페이지의 내용을 간략히 설명하는 메타 태그이다.
  • SEO 효과: 이 설명은 검색 엔진 결과 페이지(SERP)에서 페이지 제목 아래에 표시되며, 클릭률(CTR)에 큰 영향을 미친다. 잘 작성된 메타 설명은 더 많은 클릭을 유도할 수 있고, 높은 클릭률은 검색 엔진 알고리즘에 긍정적인 신호를 보내 순위를 높이는 데 도움을 줄 수 있다.

c. <meta property="og:${title, description, image}" />

  • 역할: Open Graph 프로토콜을 사용하여 소셜 미디어에서 페이지가 공유될 때 표시되는 제목, 설명, 이미지를 정의한다.
  • SEO 효과: 이 제목, 설명, 이미지는 소셜 미디어에서 페이지가 공유될 때 나타난다. 해당 기능은 사용자에게 페이지를 방문하도록 유도할 수 있으며, 이는 트래픽 증가로 이어져 SEO에 긍정적인 영향을 미칠 수 있다.
💡 Does not support SVG image - meta tag 에 이미지 형식은 svg 가 안된다!!! ⇒ png, jpg 사용

2. React Helmet 적용

a. react-helmet-async 설치

```jsx
yarn add react-helmet-async
```

b. App.js 에서 HelmetProvider를 사용하여 감싸준다.

```jsx
import React from 'react';
import { HelmetProvider } from 'react-helmet-async';
import { Outlet } from 'react-router-dom';

function App() {
  return (
    <HelmetProvider>
      <Outlet />
    </HelmetProvider>
  );
}

export default App;

```

c. 컴포넌트에서 Helmet 사용 ⇒ Header 탭에 있는 3개의 큰 컴포넌트에만 적용

```jsx
import React from 'react';
import EventIntroMain from '@/pages/eventIntro/EventIntroMain';
import EventIntroNav from '@/pages/eventIntro/EventIntroNav';
import EventIntroRewards from '@/pages/eventIntro/EventIntroRewards';
import { animationVariants } from '@/styles/FramerMotion';
import { motion } from 'framer-motion';
import { Helmet } from 'react-helmet-async';

function EventIntro() {
  return (
    <div>
      <Helmet>
        <title>캐스퍼 이벤트 소개</title>
        <meta
          name="description"
          content="캐스퍼 EV를 받을 수 있는 이벤트에 대해 자세히 알아보세요. 이벤트 참여 방법과 다양한 보상을 소개합니다."
        />
        <meta property="og:title" content="캐스퍼 이벤트 소개" />
        <meta
          property="og:description"
          content="캐스퍼 EV를 받을 수 있는 이벤트에 참여해보세요!"
        />
        <meta
          property="og:image"
          content="https://softeer4-team8.s3.ap-northeast-2.amazonaws.com/%E1%84%86%E1%85%B5%E1%84%82%E1%85%B5+%E1%84%8F%E1%85%B1%E1%84%8C%E1%85%B3+7.svg"
        />
      </Helmet>
      <EventIntroMain />
      <div className="bg-gradient-lightblue-white-vertical mt-[1px]">
        <EventIntroNav />
        <motion.div
          initial="hidden"
          animate="visible"
          variants={animationVariants}
          transition={{
            duration: 0.6,
            ease: 'easeOut',
            delay: 0.1,
          }}
        >
          <EventIntroRewards />
        </motion.div>
      </div>
    </div>
  );
}

export default EventIntro;

```

해당 코드는 예시 코드로 탭에 있는 페이지 중 하나를 맡고 있는 코드이다.

가장 부모요소 바로 아래에 Public/index.html 에서 meta태그를 적용하는 방식과 동일하게 작성하고 바깥을 **`<Helmet></Helmet>`** 으로 감싸주면 적용이 된다.

3. Robot.txt, sitemap.xml

a. Robot.txt

```jsx
User-agent: *
Allow: /public/
Sitemap: https://casper-event.store/sitemap.xml
```

robots.txt 파일은 웹사이트의 루트 디렉토리에 위치하며, 검색 엔진 크롤러(또는 봇)에게 어떤 페이지나 디렉토리를 크롤링할 수 있는지 또는 할 수 없는지를 지시한다.

이 파일은 웹사이트의 크롤링 규칙을 정의하여 검색 엔진이 어떻게 사이트를 탐색할지 결정하는 데 도움을 준다.

SEO에 미치는 영향

  1. 크롤링 제어: robots.txt 파일을 통해 특정 페이지나 디렉토리에 대한 크롤링을 차단함으로써, 검색 엔진이 중요하지 않거나 중복된 콘텐츠를 색인하지 않도록 할 수 있다. 예를 들어, 로그인 페이지나 관리자 페이지는 검색 엔진에 노출될 필요가 없으므로 이를 차단할 수 있다.
  2. 서버 리소스 절약: 크롤러가 불필요한 페이지를 크롤링하지 않도록 하여 서버 리소스를 절약할 수 있다. 이는 서버에 대한 부하를 줄이고 사이트의 성능을 유지하는 데 도움이 된다.
  3. 중복 콘텐츠 방지: 사이트 내 중복 콘텐츠가 있는 경우, 검색 엔진이 중복 페이지를 색인하는 것을 방지하여 검색 엔진의 혼동을 줄일 수 있다.

b. sitemap.xml

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://casper-event.store/</loc>
    <lastmod>2024-08-21</lastmod>
    <priority>1.0</priority>
  </url>
  <url>
    <loc>https://casper-event.store/event</loc>
    <lastmod>2024-08-21</lastmod>
    <priority>0.8</priority>
  </url>
  <url>
    <loc>https://casper-event.store/introduce</loc>
    <lastmod>2024-08-21</lastmod>
    <priority>0.6</priority>
  </url>
</urlset>

sitemap.xml 파일은 웹사이트의 모든 페이지에 대한 정보를 담고 있으며, 검색 엔진 크롤러에게 사이트의 구조를 알려준다. 이 파일은 사이트의 모든 URL을 나열하고, 각 페이지의 우선순위, 변경 날짜, 업데이트 빈도 등을 제공하여 크롤러가 페이지를 보다 효과적으로 탐색할 수 있도록 합니다.

SEO에 미치는 영향

  1. 검색 엔진 색인 향상: 검색 엔진이 웹사이트의 페이지를 보다 빠르고 정확하게 색인할 수 있도록 돕는다. 특히, 사이트 구조가 복잡하거나 페이지가 자주 업데이트되는 경우 유용하다.
  2. 우선순위 제공: 사이트맵에서 각 페이지의 중요도를 정의할 수 있어, 검색 엔진이 더 중요한 페이지를 우선적으로 크롤링하고 색인할 수 있다.
  3. 크롤러 효율성 향상: 크롤러가 사이트의 모든 페이지를 발견하고 탐색할 수 있도록 보장하여, 누락된 페이지가 없도록 한다.

4. PreRendering 적용

다양한 라이브러리를 찾아보다가

  1. react-snap
  2. react-snapshot
  3. Puppeteer와 Prerender

다음 3개의 라이브러리를 주요 사용하는 것을 확인할 수 있었다.

우선 2번인 react-snapshot 의 경우 1번과 거의 유사하지만 다운로드 수도 적고 거의 사용하지 않는다는 사실을 알 수 있었다.

1번인 react-snap 은 많이 활용되는 라이브러리였지만 CRA와 잘 통합되고 React18버전을 제대로 지원하지 않기 때문에 React의 버전을 17로 다운시켜야 한다는 단점이 있었다.

Vite + React 18 환경에서 가장 좋은 PreRendering 라이브러리

Vite와 React 18 환경에서 Hybrid Approach를 구현하려면 Puppeteer와 Prerender를 사용하는 것이 가장 유연하고 강력한 방법이다.

  1. 동적 컨텐츠 처리: Puppeteer를 사용하여 동적 컨텐츠와 사용자 상호작용을 포함한 페이지를 사전 렌더링할 수 있다.
  2. 서버 사이드 렌더링 유사 효과: 서버 사이드에서 페이지를 렌더링하여 SEO와 초기 로딩 성능을 개선할 수 있다.
  3. Vite와의 호환성: Vite 프로젝트와 잘 통합될 수 있으며, 설정을 통해 Vite 빌드 결과물에 적용할 수 있다.

실행 순서

a. 패키지 설치

```jsx
yarn add puppeteer
```

b. vite.config.js 파일 수정 ( vite 환경에서만 !!! )

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
import { resolve } from 'path';
import svgr from 'vite-plugin-svgr';
import prerender from '@prerenderer/rollup-plugin';
import dotenv from 'dotenv';

dotenv.config();

export default defineConfig({
  plugins: [
    react(),
    svgr(),
    prerender({
      routes: [
        '/',
        '/event',
        '/event/worldCup',
        '/event/miniQuiz',
        '/introduce',
      ],
      renderer: '@prerenderer/renderer-puppeteer',
      rendererOptions: {
        maxConcurrentRoutes: 1,
        renderAfterTime: 500,
      },
      postProcess(renderedRoute) {
        const apiUrl = process.env.VITE_API_URL;
        renderedRoute.html = renderedRoute.html
          .replace(/http:/i, 'https:')
          .replace(/(https:\/\/)?(localhost|127\.0\.0\.1):\d*/i, apiUrl);
      },
    }),
  ],
  resolve: {
    alias: [
      { find: '@', replacement: resolve(__dirname, 'src') },
      { find: '@pages', replacement: resolve(__dirname, 'src/pages') },
    ],
  },
});

위의 코드가 우리 프로젝트의 전체 vite.config.js 이며 prerender를 import 하고

routes에 적용한 주소를 적어주고 postProcess 에 서버를 적어줘야 한다.

이때 서버를 로컬에서 돌리면 apiUrl 대신 localhost:3000을 적어주면 되고 만약 배포되어 있는 서버인 경우

.env 파일에서 가져와야 하는데 vite.config.js. 파일은 빌드 도구 이기때문에 직접적으로 가져올 수 있는 방법이 없다.

따라서 api 통신에서 사용하는 방법과 같이 가져오게 되면 스크린샷 2024-08-21 오후 2 16 53

위와 같은 에러를 볼 수 있다.

“VITE_API_URL” 이 undefined이다.

해결 방법

  1. dotenv 패키지 설치

    yarn add dotenv
  2. vite.config.js 파일 수정

    import dotenv from 'dotenv';
    
    dotenv.config();
  3. apiUrl 가져오기

    const apiUrl = process.env.VITE_API_URL;

를 통해 해결할 수 있다.


결론

lighthouse 로 적용하기 전의 SEO 점수를 확인했을 때

스크린샷 2024-08-21 오전 10 57 48

lighthouse 로 적용한 후 SEO 점수를 확인했을 때

스크린샷 2024-08-25 오후 5 48 51

SEO 점수가 100점까지 오른 것을 확인해 볼 수 있다.

Clone this wiki locally