티스토리 뷰
들어가며
WegglePlus 팀은 블로그 콘텐츠를 통한 검색 유입 확대와 서비스 성장을 목표로 새로운 마케팅 프로젝트를 시작했습니다. 이 프로젝트의 핵심은 **SEO(검색엔진 최적화)**를 통해 안정적인 트래픽을 확보하고, 이를 WegglePlus 서비스 유입으로 연결하는 것입니다.
오늘은 SEO의 기본 중 기본, Sitemap과 Robots.txt 구현 과정을 공유합니다.
Sitemap과 Robots.txt가 왜 중요할까?
Sitemap.xml
Sitemap은 웹사이트의 페이지 목록을 검색엔진에 알려주는 XML 파일입니다. 검색엔진 크롤러가 사이트 구조를 빠르게 파악하고, 새로운 콘텐츠를 효율적으로 색인할 수 있도록 도와줍니다.
<https://weggle-plus.co.kr/blog>
2026-01-10
weekly
0.8
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
<https://weggle-plus.co.kr/>
2026-01-10T11:50:57.735Z
weekly
0.8
<https://weggle-plus.co.kr/blog>
...
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)도 함께 준비하고 있습니다.
About WegglePlus
WegglePlus는 문제를 정의하고, 이를 해결하는 여러 개의 서비스를 설계·개발·운영합니다.
이 해당 글은 그 과정에서의 기술적 선택과 시행착오를 공유합니다.
https://weggle-plus.co.kr
Weggle Plus
weggle-plus.co.kr
'개발 일기' 카테고리의 다른 글
| AI 팀원과 일하는 법 — Skills로 가상 소프트웨어 회사 만들기 (0) | 2026.02.21 |
|---|---|
| WegglePlus 1.0 — 3개월의 실패 이후, 다시 시작하기 (0) | 2026.02.10 |
| 블로그의 RSS 피드 구현하기 (0) | 2026.01.09 |
| Refresh Token은 쿠키, Access Token은 메모리에 (1) | 2025.12.19 |
| Spring Locale 공통화 여정 (0) | 2025.11.10 |
