블로그가 어떻게 동작하는지 알아보기 - SEO

블로그가 어떻게 동작하는지 알아보기 - SEO

SEO
2024년 09월 05일

SEO를 알아보자 Search Engine Optimization

SEO는 한국어로 검색 엔진 최적화입니다. 네이버나 구글에서 검색했을 때 검색 엔진이 더 잘 찾을 수 있도록 도와주는 역할을 합니다.
SEO에는 크게 3가지 종류가 있습니다:
  • Technical SEO
  • On-Page SEO
  • Off-page SEO

Technical SEO 이란

검색을 하기 위해 검색엔진 봇이 돌아다니는데, 이 봇들이 쉽게 크롤링하고 인덱싱할 수 있도록 기술적 요소를 최적화하는 작업입니다. 예를 들어, 사이트 로딩 속도, 모바일 친화성, SSL 인증서, 사이트맵 등이 포함됩니다.

On-Page SEO 이란

웹사이트 내부의 콘텐츠와 소스를 최적화하는 작업입니다. 여기에는 키워드, 메타 태그, 이미지 최적화, 콘텐츠 품질 등이 포함됩니다.

Off-page SEO 이란

웹사이트 외부에서 최적화 작업을 하는 것으로, 다른 웹사이트들이 내 사이트에 링크를 걸면 사이트의 권위를 높이고 검색 엔진에서 높은 점수를 얻게 됩니다.
웹 개발자가 할 수 있는 최적화 작업은 위 3가지 중 2가지입니다. 이제 이 두 가지를 살펴보겠습니다.

Technical SEO 최적화 작업을 알아보자.

전 글에서 사이트 로딩 속도에 대해 언급했었죠. Google의 LighthousePerformance가 사이트 속도를 측정하는 주요 지표입니다.
Lighthouse를 사용하면 사이트의 성능을 분석하고 개선할 수 있는 구체적인 항목들을 확인할 수 있습니다.
Performance

위 사진은 제 블로그 Performance 점수입니다.


Performance 세부 항목에는 FCP, LCP, TBT, CLS, SI 총 5개가 있습니다. 하나씩 살펴보겠습니다:
  • FCP : 웹 페이지에서 첫 번째 콘텐츠가 렌더링되기까지 걸리는 시간
  • LCP : 페이지에서 가장 큰 콘텐츠가 렌더링되는 시간
  • TBT : 페이지가 로드되는 동안 사용자가 상호작용할 수 없는 시간의 총합
  • CLS : 페이지 로드 중 레이아웃이 얼마나 자주, 얼마나 크게 이동하는지를 측정
  • SI : 페이지가 시각적으로 완성되는 데 걸리는 시간
현재 블로그는 SSG로 렌더링되기 때문에 빠를 수밖에 없습니다.

Next.js App Router 에서 SiteMap 생성방법을 알아보자

sitemap.xml 공식문서를 보면 ts => XML으로 포맷팅을 쉽게 할 수 있도록 만들어졌습니다.
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://acme.com</loc>
    <lastmod>2023-04-06T15:02:24.021Z</lastmod>
    <changefreq>yearly</changefreq>
    <priority>1</priority>
  </url>
  <url>
    <loc>https://acme.com/about</loc>
    <lastmod>2023-04-06T15:02:24.021Z</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.8</priority>
  </url>
  <url>
    <loc>https://acme.com/blog</loc>
    <lastmod>2023-04-06T15:02:24.021Z</lastmod>
    <changefreq>weekly</changefreq>
    <priority>0.5</priority>
  </url>
</urlset>
간단한 페이지들은 수동으로 입력해도 됩니다. 그러나 블로그처럼 많은 게시글을 올리는 사이트에서는 하나하나 입력하기 어려우므로 Next.js에서 제공하는 함수를 사용해보겠습니다.
import type { MetadataRoute } from 'next';
import { useReadMdx as ReadMDX } from '../hooks/useReadMdx';
import { MDX } from '@/interface';
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const baseUrl = 'https://bittenlog.vercel.app';

  const posts: MDX.Metadata[] = (await ReadMDX()) as MDX.Metadata[];
  const indexPage = {
    url: baseUrl,
    lastModified: new Date().toISOString().split('T')[0],
  };
  const article = posts?.map((post) => {
    return {
      url: `${baseUrl}/article/${post.path}`,
      lastModified: new Date(post.date).toISOString().split('T')[0],
    };
  });

  return [indexPage, ...article];
}
app/sitemap.ts를 생성한 후 XML 포맷팅을 맞추기만 하면, 블로그 Sitemap 처럼 output을 생성할 수 있습니다.
이게 끝이야?
기본적인 설정은 끝났지만, sitamp.xml에는 한계가 있습니다. 최대 50,000개의 Sitemap을 포함할 수 있지만 크기는 50MB(52,428,800바이트)를 초과할 수 없습니다라고 명시되어 있습니다.
공식 문서를 보고 응용해보겠습니다.
import type { MetadataRoute } from 'next';

export async function generateSitemaps() {
  return [{ id: 'test1' }, { id: 'test2' }, { id: 'test3' }];
}

export default async function sitemap({ id }: { id: string }): Promise<MetadataRoute.Sitemap> {
  const products = new Array(5000).fill(null).map((_, index) => ({
    id: index + 1,
    date: new Date().toISOString(),
  }));
  return products.map((product) => ({
    url: `http://localhost:3000/product/${product.id}`,
    lastModified: product.date,
  }));
}
페이지에 사용되는 ID 목록을 생성하고, ID에 따른 사이트맵을 생성합니다.
 ● /sitemap/[__metadata_id__]           0 B                0 B
    ├ /sitemap/test1.xml
    ├ /sitemap/test2.xml
    └ /sitemap/test3.xml
이렇게 하면 SiteMap이 여러 개 생성되고, 파일 한 개당 5000개씩 채워져서 output으로 나온 SiteMap을 구글에 등록하면 됩니다. 이 블로그는 50,000개 정도의 게시글을 올릴 일이 없으니 간단하게 적용했습니다.

On-Page SEO 최적화 작업을 알아보자.

메타 태그

사이트 링크를 공유하든 검색창에서 처음으로 마주하는 것이 메타 태그이기 때문에 메타 태그는 가장 중요합니다. 그러면 Next.js에서 메타 태그를 어떻게 간단히(?) 설정할 수 있는지 알아보겠습니다.
다시 공식문서로 가보면:
export const metadata = {
  title: 'Blog',
  openGraph: {
    title: 'Blog',
  },
};
위와 같은 형식으로 되어 있습니다. 이제 블로그에 적용해보겠습니다.
export const metadata: Metadata = {
  metadataBase: new URL('https://bittenlog.vercel.app'),
  title: {
    default: 'Bitten Dev',
    template: '%s | Bitten Dev',
  },

  category: 'tech blog',
  description: '성장 욕구가 많은 개발자로서, 공부한 내용을 정리하는  개발 블로그 입니다.',
  authors: [{ name: '비튼', url: 'https://bittenlog.vercel.app' }],

  openGraph: {
    images: ogImage.src,
    title: {
      default: 'Bitten Dev',
      template: '%s | Bitten',
    },
    description: '성장 욕구가 많은 개발자로서, 공부한 내용을 정리하는 개발 블로그 입니다.',
  },
  verification: {
    google: 'uBovfhvYdbEJvqXAGE44EfvyNswgNRSOmXXEApmtV_g',
  },
};
app/layout.tsx
블로그에는 기본적인 것들만 설정해놓았습니다. title.template을 보면 %s | Bitten Dev라고 되어 있는데, %s는 변수를 나타냅니다.
export async function generateMetadata({ params }: { params: { slug: string } }): Promise<Metadata> {
  const data = await getFiles(params.slug);
  if (!data) return {};
  return {
    title: data.meta.title,
    description: data.meta.description,
    openGraph: {
      images: data.meta.thumbnail,
    },
    keywords: [...(data.meta.tags ?? [])],
  };
}
app/article[slug]/page.tsx 에서 Metadata설정한 코드입니다.
이렇게 title만 정의해 놓으면 | Bitten Dev는 계속 뒤에 따라다니게 됩니다. title을 정하지 않으면 title.default의 값인 Bitten Dev으로 나오게 됩니다.
category 태그는 웹사이트의 종류나 범주를 명시하면 됩니다. description 태그는 웹사이트의 설명을 적으면 검색 시 미리보기로 보여집니다. authors 태그는 필수는 아니지만, 작성자의 정보를 추가하면 웹 문서의 출처를 명확히 할 수 있습니다. keywords 태그는 이제 사용하지 않습니다. 구글에서 사용하지 않는다고 명시해놨다.

openGrap

소셜 미디어에서 가장 먼저 보여지는 항목입니다. title , description은 그대로 사용하면 됩니다. 원래는 상속되었지만, 테스트할 때 문제가 있어 적용했습니다.
images가 가장 중요합니다. 파일 형식은 JPEG, PNG, GIF를 지원하며, PNG로 하는 것이 좋습니다. 해상도는 원래 200 X 200 이였지만 최근에는 1200 X 630 을 권장합니다.

Off-page SEO 최적화 작업을 알아보자

이 작업은 마케팅이 중요하고 협력사끼리 서로 링크를 공유하여 검색엔진 순위를 올리는 방식입니다. 공유가 많을 만한 글이 아닌 이상 올리기 어렵고, 백링크를 구매하여 순위를 올리기도 합니다.
다른 웹사이트에 링크를 남발하거나 구매할 수 있지만, 이상한 웹사이트에 남발하면 오히려 본인 웹사이트에 나쁜 영향을 미칠 수 있습니다. 최적화에 가장 좋은 방법은 돈을 주고 업체에 맡기는 것이라고 생각합니다.

마치면서

오늘은 Next.js의 함수를 이용하여 SEO 최적화를 알아보았습니다. 앞으로는 CS 기초 다지기를 들어갈 것이므로, 개발 CS 관련 글을 작성할 예정입니다.