이로

Vue3, vite 정적, 동적 sitemap , sitemap.xml 생성하기 본문

컴퓨터/Vue

Vue3, vite 정적, 동적 sitemap , sitemap.xml 생성하기

利路 2024. 11. 25. 15:01
반응형

정적 사이트맵 생성

정적 사이트 맵 생성은 특정 파일에 내가 원하는 페이지만 직접 작성하는 방법입니다.


Case 1. vite.config.ts에 sitemap 내용 직접 정의

npm install -D vite-plugin-sitemap
import { defineConfig } from 'vite' 
import vue from '@vitejs/plugin-vue' 
import { sitemap } from 'vite-plugin-sitemap' 

export default defineConfig({ 
  plugins: [
    vue()
    , sitemap({
      hostname: 'https://your-domain.com', // 라우트 직접 정의 
      urls: [{
        url: '/'
        , lastmod: new Date().toISOString()
        , changefreq: 'daily'
        , priority: 1.0 
      }, 
      { 
        url: '/about'
        , lastmod: new Date().toISOString()
        , changefreq: 'weekly'
        , priority: 0.8 
      }, 
      { 
        url: '/contact', 
        lastmod: new Date().toISOString(), 
        changefreq: 'monthly', 
        priority: 0.5 
      } 
    ]
    , exclude: ['/admin', '/private'], }), ], })

 

Case 2. vite.config.ts에서 index.ts파일 읽어와 자동으로 세팅하고, URL 예외처리할 내용만 수정하기.

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import viteCompression from 'vite-plugin-compression';
import { resolve } from 'path';
import { writeFileSync, readFileSync  } from 'fs';
import * as ts from 'typescript';

function extractRoutePaths(fileContent: string): string[] {
  const paths: string[] = [];

  // TypeScript 소스 파일을 파싱
  const sourceFile = ts.createSourceFile(
      'index.ts',
      fileContent,
      ts.ScriptTarget.Latest,
      true
  );

  // routes 배열을 찾아서 경로 추출
  function visit(node: ts.Node) {
    if (ts.isArrayLiteralExpression(node)) {
      const routes = node.elements.map(element => {
        if (ts.isObjectLiteralExpression(element)) {
          const pathProperty = element.properties.find(prop =>
              ts.isPropertyAssignment(prop) &&
              prop.name.getText(sourceFile) === 'path'
          );

          if (pathProperty && ts.isPropertyAssignment(pathProperty)) {
            const pathValue = pathProperty.initializer.getText(sourceFile);
            // 따옴표 제거 및 동적 라우트 필터링
            const path = pathValue.replace(/['"]/g, '');
            if (!path.includes(':')) {
              return path;
            }
          }
        }
        return null;
      }).filter(Boolean) as string[];

      paths.push(...routes);
    }

    ts.forEachChild(node, visit);
  }

  visit(sourceFile);
  return paths;
}

function createSitemapPlugin(options: {
  hostname: string;
  routerPath: string;  // router/index.ts 파일 경로
  exclude?: string[];
  additionalPaths?: string[];
  outFile?: string;
  lastmod?: string;
}) {
  const {
    hostname,
    routerPath,
    exclude = [],
    additionalPaths = [],
    outFile = 'sitemap.xml',
    lastmod = new Date().toISOString()
  } = options;

  return {
    name: 'vite-plugin-sitemap',
    apply: 'build',
    closeBundle: async () => {
      try {
        // router/index.ts 파일 읽기
        const routerContent = readFileSync(routerPath, 'utf-8');

        // 라우트 경로 추출
        const paths = extractRoutePaths(routerContent)
            .filter(path => {
              // 제외할 경로 필터링
              return !exclude.some(pattern =>
                  path.match(new RegExp(pattern.replace('*', '.*')))
              );
            });

        // 모든 경로 합치기 (router 경로 + 추가 경로)
        const allPaths = [...paths, ...additionalPaths]
            .filter(path => path && path !== '/')  // 빈 경로와 루트 경로 제외
            .map(path => path.startsWith('/') ? path : `/${path}`); // 경로 정규화

        const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${allPaths.map(path => `  <url>
    <loc>${hostname}${path}</loc>
    <lastmod>${lastmod}</lastmod>
  </url>`
            ).join('\n')}
</urlset>`;

        writeFileSync(resolve(process.cwd(), 'dist', outFile), sitemap);
      } catch (e) {
        console.error('Failed to generate sitemap:', e);
      }
    }
  };
}

export default defineConfig(({ command, mode }) => {
// 중략 ...
  return {
// 중략...
    plugins: [
    // 중략...
      createSitemapPlugin({
        hostname: 'https://your-domain.com',
        routerPath: resolve(__dirname, 'src/router/index.ts'),  // router 파일 경로 지정
        exclude: [
          '/admin',    // 관리자 페이지 제외
          '/admin/*',  // 관리자 페이지 제외
          '/login',    // 로그인 페이지 제외
        ],
        additionalPaths: [], // 필요한 경우 추가 경로
        outFile: 'sitemap.xml',
        lastmod: new Date().toISOString()
      }),
   // 중략...
   ]
  }
})

 

함께 보면 좋은 글

Sitemap이란?

 

반응형
Comments