SEO를 위한 나의 몸부림

Next의 SEO를 향상 시키는 방법을 다룹니다.

2023-02-28

SEO 없는 내 포스트

개요

블로그에 SEO를 적용하기 위해 공부한 내용과 제가 블로그에 적용한 내용을 정리합니다.

SEO란 뭘까?

SEO는 Search Engine Optimization의 약자로 검색 엔진 최적화라는 뜻을 갖습니다. 검색 유저의 의도를 이해하고, 의도에 맞게 웹 페이지의 콘텐츠를 제작하는 과정이라고 할 수 있습니다.

또 페이지가 검색 결과 페이지 상단에 잘 노출될 수 있게, 시맨틱 태그와 구조를 개선해 트래픽을 늘리는 방법론입니다.

SEO 과정

SEO의 과정을 알기 위해선 검색 엔진이 웹사이트 품질을 결정하는 과정을 알아야 합니다.

검색 엔진은 3 단계로 작동합니다. (구글 기준)

1. 크롤링

  • 크롤러라는 자동화된 프로그램을 사용해, 인터넷에서 찾은 페이지로부터 텍스트, 이미지, 동영상을 다운로드합니다.

2. 색인 생성

  • 페이지의 텍스트, 이미지, 동영상 파일을 분석하고 색인에 정보를 저장합니다.

3. 결과 게재

  • 검색어와 관련된 정보를 반환해 게재합니다.

크롤링색인 생성을 좀 더 자세히 살펴보겠습니다.

크롤링

검색엔진은 계속해서 새 페이지와 업데이트된 페이지를 검색해 파악된 페이지 목록에 웹페이지를 등록합니다. 이런 과정을 URL 검색이라고 합니다. 기존에 방문한 적이 있는 페이지는 파악된 페이지 목록에 추가되어 있습니다. 다른 페이지의 발견은 새 페이지로 연결되는 링크를 따라갈 때 발견됩니다. 또 사이트 소유자가 사이트맵을 제출해 발견되는 페이지도 있습니다.

색인 생성

페이지가 크롤링 되면 검색 엔진은 페이지의 내용을 파악하려고 합니다. 이 단계를 색인 생성이라고 하며 title, alt 속성 등 핵심 콘텐츠·태그와 속성을 처리하고 분석하는 작업입니다.

SEO가 중요한 이유

우리는 궁금한 것이 생기면 구글 혹은 네이버 등 검색 엔진에 궁금한 키워드를 검색합니다.

아 뭐더라?

이때, 대부분의 사람들은 검색 결과 상위에 노출된 페이지를 누르고 열람합니다. 물론 광고를 사용해 트래픽을 올릴 수 있지만 (paid search) 대부분의 사람들은 자연적으로 트래픽이 높은 결과 (organic search)를 선호합니다. SEO를 잘하면 비용을 들이지 않고도 페이지를 검색 결과 상위에 지속적으로 노출시킬 수 있습니다.

즉 아무리 좋은 콘텐츠를 갖는 사이트라도 SEO가 좋지 않다면, 검색 결과에서 노출되지 않을 확률이 높습니다.

메타 태그

메타 태그란 검색 엔진에 페이지에 대한 추가 정보를 제공하는 데 사용되는 HTML 태그입니다. meta태그는 HTML의 <head> 태그 안에 추가됩니다. HTML 문서가 어떤 내용이며, 키워드, 만든 사람 등의 메타데이터를 제공합니다.

Next는 13.2 버전 이후부터 빌트인으로 SEO를 위한 메타데이터를 만들어주는 기능을 지원합니다. 메타데이터는 어떤 page.tsxlayout.tsx에서 사용 가능합니다.

charsetviewport은 설정해 주지 않아도 기본적으로 적용됩니다!

<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />

Next를 이용하면, 두 가지의 방법으로 메타데이터를 생성할 수 있습니다.

  1. 정적 메타데이터 (Static)

정적으로 메타데이터를 생성하는 방법으로, 페이지 내부에서 metadataexport 하여 메타데이터 객체를 생성합니다. 이때 template 속성을 이용하면 방문하는 페이지 별로 타이틀이 바뀌게 됩니다.

layout.tsx
import type { Metadata } from "next";
 
export const metadata: Metadata = {
  title: {
    default: "Yujiseok",
    template: "%s | Yujiseok", // 방문하는 페이지 별 타이틀 변경
  },
  description: "공부하는 것을 기록하고 공유하는 유지석의 개인 기술 블로그",
  icons: {
    shortcut: "/favicon.ico",
  },
  openGraph: {
    title: {
      absolute: "유지석",
    },
    description: "공부하는 것을 기록하고 공유하는 유지석의 개인 기술 블로그",
    url: "https://www.yujiseok.blog/",
    locale: "ko_KR",
    type: "website",
  },
};
  1. 동적 메타데이터 (Dynamic)

[slug]와 같이 동적 라우팅을 할 경우에 동적인 값을 받아오기 위해 사용하는 방법입니다. 메타데이터를 generateMetadata 함수를 사용하여 fetch 해 동적으로 생성합니다.

제 블로그에 동적으로 메타데이터를 생성해야 할 페이지는 각각의 포스트 페이지입니다. 메타데이터를 생성하기 위해선 우선적으로 slug가 필요합니다.

slug의 경우 generateStaticParams 함수를 사용해 개별적으로 생성합니다. find 메서드를 사용해 slug와 맞는 포스트를 찾습니다. 찾아진 포스트에서 데이터를 추출하여 메타데이터에 맞는 형식으로 반환해 줍니다.

[slug]/page.tsx
export async function generateStaticParams() {
  return allPosts.map((post) => ({
    slug: post.slug,
  }));
}
 
export async function generateMetadata({
  params,
}: {
  params: { slug: string };
}): Promise<Metadata | undefined> {
  const post = allPosts.find((post) => post.slug === params.slug);
  if (!post) {
    return;
  }
  const {
    title,
    publishedAt: publishedTime,
    summary: description,
    slug,
  } = post;
 
  return {
    title,
    description,
    openGraph: {
      title: { absolute: title },
      description,
      type: "article",
      publishedTime,
      url: `https://www.yujiseok.blog/post/${slug}`,
    },
  };
}

✨ openGraph는 sns나 메신저에 링크를 공유할 때, 컨텐츠의 미리 보기를 지원해 주는 태그입니다.

위와 같은 과정을 거치게 되면, Next가 메타데이터를 생성해 줍니다.

동적으로 생성된 메타데이터

사이트맵

사이트맵은 사이트에 있는 페이지, 동영상 및 기타 파일과 그 관계에 관한 정보를 제공하는 파일입니다. 구글과 같은 검색 엔진은 사이트맵을 통해 더 효율적으로 크롤링을 할 수 있게 됩니다.

사이트의 페이지가 제대로 링크 되어있다면 검색 엔진은 대부분의 사이트를 제대로 찾을 수 있습니다. 하지만 사이트맵을 사용하면, 규모가 큰 사이트나 전문화된 파일의 크롤링 효율을 상승시킬 수 있습니다.

사이트맵은 규모가 큰 사이트에 필요하지만, 사이트맵을 동적으로 생성하는 것을 구현해 보기 위해 직접 사이트맵을 생성해 보기로 하였습니다.

아래의 코드는 가장 기본적인 xml 사이트맵입니다.

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://www.example.com</loc>
    <lastmod>2023-02-28</lastmod>
  </url>
</urlset>

각 태그의 설명은 아래와 같습니다.

  • urlset: 파일을 캡슐화하고 현재 프로토콜 표준을 참조합니다.
  • url: 각 url 항목의 상위 태그입니다.
  • loc: 페이지의 url
  • lastmod: 파일을 마지막으로 수정한 날짜입니다.

위 태그 외에도 changefreq, priorty 등의 선택 옵션 태그가 있습니다.

🚨 아래의 생성 방식은 레가시한 방식입니다. 넥스트는 현재 사이트맵robots.txt를 생성하는 빌트인 API를 제공합니다. 빌트인 API를 사용해 구현하는 방식은 이 포스트에서 확인하실 수 있습니다.

사이트맵을 생성하기 위해 nodefs 모듈을 가져옵니다. 현재 작업 디렉토리의 경로를 사용해 mdx 파일들이 있는 content 폴더를 읽어들입니다. 모든 파일들을 map 메서드를 사용해 순회하면서, .mdx 확장자를 replace 메서드를 사용해 제거합니다.

이렇게 반환된 slug들을 postUrls에 템플릿 리터럴을 사용해 담아줍니다. xml 태그 코드에 postUrls을 역시 템플릿 리터럴을 사용해 추가한 후 public 경로에 파일을 생성합니다.

lib/sitemap.ts
import fs from "fs";
 
const getDate = new Date().toISOString();
 
function createSiteMap() {
  const path = process.cwd();
 
  const allPosts = fs.readdirSync(`${path}/content`);
  const slugs = allPosts.map((post) => post.replace(".mdx", ""));
 
  const postUrls = slugs
    .map(
      (slug) => `<url>
        <loc>https://www.yujiseok.blog/post/${slug}</loc>
        <lastmod>${getDate}</lastmod>
      </url>`
    )
    .join("");
 
  const generatedSitemap = `<?xml version="1.0" encoding="UTF-8"?>
    <urlset
      xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 
      http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"
    >
      <url>
        <loc>https://www.yujiseok.blog/</loc>
      </url>
      <url>
        <loc>https://www.yujiseok.blog/about</loc>
      </url>
      <url>
        <loc>https://www.yujiseok.blog/post</loc>
      </url>
      ${postUrls}
    </urlset> `;
 
  fs.writeFileSync("public/sitemap.xml", generatedSitemap, "utf-8");
}
 
createSiteMap();

빌드 직전에 스크립트를 이용해 사이트맵을 public 디렉토리에 생성해 줍니다.

package.json
  "scripts": {
    // ...
    "sitemap": "ts-node --project tsconfig.node.json ./lib/sitemap.ts",
    "build": "pnpm sitemap && next build",
  }

생성된 사이트맵은 구글서치콘솔에 등록해 줍니다.

동적으로 생성된 메타데이터

robots.txt

robots.txt는 크롤러에게 사이트 및 웹페이지를 수집할 수 있도록 허용하거나 제한하는 .txt 파일입니다. robots.txt는 사이트맵과 함께 public 디렉토리에 추가해 줍니다.

User-agent: * ➡️ 모든 크롤러 허용
Allow: / ➡️ 모든 디렉토리 허용
Sitemap: https://yujiseok.blog/sitemap.xml

끝으로

평소 한 번도 고민해 보지 않은 분야였는데, 블로그를 만들며 SEO가 정말 중요하며 간과하지 말아야 할 것이라는 것을 알게 되었습니다. 언젠가 제 블로그도 구글에 검색하였을 때 검색 결과 최상단에 나올 그날을 위해 열심히 SEO를 향상시켜야겠습니다.


출처

  • https://developers.google.com/search/docs/fundamentals/how-search-works?hl=ko
  • https://beta.nextjs.org/docs/api-reference/metadata
  • https://www.sitemaps.org/ko/protocol.html
  • https://searchadvisor.naver.com/guide/seo-basic-robots