들어가며
WegglePlus 팀은 블로그 콘텐츠를 통한 검색 유입 확대와 서비스 성장을 목표로 새로운 마케팅 프로젝트를 시작했습니다. 이 프로젝트의 핵심은 SEO(검색엔진 최적화) 를 통해 안정적인 트래픽을 확보하고, 이를 WegglePlus 서비스 유입으로 연결하는 것입니다.
오늘은 SEO의 기본 중 기본, Sitemap과 Robots.txt 구현 과정을 공유합니다.
Sitemap과 Robots.txt가 왜 중요할까?
Sitemap.xml
Sitemap은 웹사이트의 페이지 목록을 검색엔진에 알려주는 XML 파일입니다. 검색엔진 크롤러가 사이트 구조를 빠르게 파악하고, 새로운 콘텐츠를 효율적으로 색인할 수 있도록 도와줍니다.
<url>
<loc>https://weggle-plus.co.kr/blog</loc>
<lastmod>2026-01-10</lastmod>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
</url>
Robots.txt
Robots.txt는 검색엔진 크롤러에게 "어디를 크롤링해도 되고, 어디는 안 되는지" 알려주는 파일입니다. 관리자 페이지나 비공개 영역을 검색 결과에서 제외할 때 사용합니다.
User-agent: *
Allow: /
Disallow: /admin/
Sitemap: https://weggle-plus.co.kr/sitemap.xml
Vite + React 환경에서의 구현
WegglePlus는 Vite + React 기반의 CSR(Client-Side Rendering) 애플리케이션입니다. Next.js처럼 빌드 타임에 자동으로 sitemap을 생성해주지 않기 때문에, 직접 구현이 필요했습니다.
1. vite-plugin-sitemap 설치
pnpm add vite-plugin-sitemap -D
2. 라우트 정의 파일 생성
sitemap에 포함할 경로를 관리하기 위해 별도의 설정 파일을 만들었습니다. 이렇게 하면 라우트 추가/삭제 시 sitemap 포함 여부를 명확하게 관리할 수 있습니다.
// src/config/sitemap-routes.ts
export interface SitemapRouteDefinition {
path: string;
sitemap?: boolean;
children?: SitemapRouteDefinition[];
}
export const sitemapRouteDefinitions: SitemapRouteDefinition[] = [
{
path: '/',
sitemap: false, // 루트는 플러그인이 자동 추가
children: [
{ path: 'update-notes', sitemap: true },
{ path: 'update-notes/:id', sitemap: false }, // 동적 라우트 제외
{ path: 'announcements', sitemap: true },
],
},
{
path: '/blog',
sitemap: true,
children: [
{ path: 'posts/:id', sitemap: false }, // 동적 라우트 제외
],
},
{ path: '/job-skill', sitemap: true },
{ path: '/auth', sitemap: false }, // 인증 페이지 제외
{ path: '/admin', sitemap: false }, // 관리자 페이지 제외
// ...
];
function extractSitemapRoutes(
routes: SitemapRouteDefinition[],
basePath = ''
): string[] {
const sitemapRoutes: string[] = [];
for (const route of routes) {
const fullPath = route.path.startsWith('/')
? route.path
: `${basePath}/${route.path}`.replace(/\/+/g, '/').replace(/\/$/, '') || '/';
const isDynamic = fullPath.includes(':');
if (route.sitemap && !isDynamic) {
sitemapRoutes.push(fullPath);
}
if (route.children) {
sitemapRoutes.push(...extractSitemapRoutes(route.children, fullPath));
}
}
return sitemapRoutes;
}
export function getSitemapRoutes(): string[] {
return extractSitemapRoutes(sitemapRouteDefinitions);
}
sitemap: true/false로 포함 여부를 명시적으로 관리:id와 같은 동적 라우트는 자동으로 제외- 중첩 라우트 구조 지원
3. Vite 설정에 플러그인 추가
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import Sitemap from 'vite-plugin-sitemap';
import { getSitemapRoutes } from './src/config/sitemap-routes';
const HOSTNAME = 'https://weggle-plus.co.kr';
export default defineConfig({
plugins: [
react(),
Sitemap({
hostname: HOSTNAME,
dynamicRoutes: getSitemapRoutes(),
changefreq: 'weekly',
priority: 0.8,
lastmod: new Date(),
robots: [
{ userAgent: '*', allow: '/', disallow: '/admin/' }
],
}),
],
});
중요: robots 옵션을 설정하지 않으면 플러그인이 기본 robots.txt를 생성하면서 기존 설정을 덮어씁니다. /admin/ 차단 같은 규칙이 있다면 반드시 여기서 명시해야 합니다.
빌드 결과 확인
pnpm build
빌드 후 dist 폴더에 생성된 파일들:
dist/sitemap.xml
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://weggle-plus.co.kr/</loc>
<lastmod>2026-01-10T11:50:57.735Z</lastmod>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://weggle-plus.co.kr/blog</loc>
...
</url>
<!-- 총 29개 URL -->
</urlset>
dist/robots.txt
User-agent: *
Allow: /
Disallow: /admin/
Sitemap: https://weggle-plus.co.kr/sitemap.xml
마무리
이번 작업으로 WegglePlus의 SEO 기반을 마련했습니다. Sitemap과 Robots.txt는 검색엔진 최적화의 첫걸음이지만, 이것만으로는 충분하지 않습니다. 검색엔진뿐 아니라 ChatGPT, Perplexity 같은 AI 검색에도 노출되기 위해 GEO (Generative Engine Optimization) 와 AEO(Answer Engine Optimization) 도 함께 준비하고 있습니다.