home-page/vite.config.ts

147 lines
4.2 KiB
TypeScript

import { fileURLToPath, URL } from 'node:url'
import { defineConfig, Terser } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import minipic from 'vite-plugin-minipic'
import Markdown from 'vite-plugin-md'
// @ts-ignore
import MarkdownItKatex from 'markdown-it-katex'
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'
import path from 'node:path'
import { getStaticRoutes } from './src/router/routes';
import matter from 'gray-matter';
import expandableMediaPlugin from './src/plugins/markdown-it-expandable-media'
import blogInfoPlugin from './src/plugins/markdown-it-blog-info';
import mermaidSSR from './src/plugins/markdown-it-mermaid-ssr';
import hljs from 'highlight.js'
// https://vite.dev/config/
export default defineConfig({
plugins: [
vue({
include: [/\.vue$/, /\.md$/],
}),
vueJsx(),
{
name: 'generate-sitemap-and-robots',
closeBundle: async () => {
// 获取静态路由
const staticRoutes = getStaticRoutes();
// 读取所有 Markdown 文件并解析 frontmatter
const blogDir = path.resolve(__dirname, 'src/blogs');
const blogFiles = readdirSync(blogDir).filter(file => file.endsWith('.md'));
const blogRoutes = blogFiles.map(file => {
const content = readFileSync(path.join(blogDir, file), 'utf-8');
const { data } = matter(content);
return {
path: encodeURI('/blogs/' + data.title + '.md'),
name: data.title,
changefreq: 'weekly',
priority: 0.7,
};
});
// 合并所有路由
const allRoutes = [...staticRoutes, ...blogRoutes];
const WEBSITE_URL = 'https://xn--876a.net';
// 生成 sitemap.xml
let sitemap = '<?xml version="1.0" encoding="UTF-8"?>\n';
sitemap += '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n';
allRoutes.forEach(route => {
sitemap += ' <url>\n';
sitemap += ` <loc>${WEBSITE_URL}${route.path}</loc>\n`;
sitemap += ` <lastmod>${new Date().toISOString().split("T")[0]}</lastmod>\n`;
sitemap += ` <changefreq>${route.changefreq}</changefreq>\n`;
sitemap += ` <priority>${route.priority}</priority>\n`;
sitemap += ' </url>\n';
});
sitemap += '</urlset>';
// 生成 robots.txt
let robotsTxt = '';
robotsTxt += 'User-agent: *\n';
robotsTxt += 'Allow: /\n';
robotsTxt += '\n';
// 可以添加自定义的 Disallow 规则
// robotsTxt += 'Disallow: /admin/\n';
// robotsTxt += 'Disallow: /private/\n';
robotsTxt += '\n';
robotsTxt += `Sitemap: ${WEBSITE_URL}/sitemap.xml\n`;
// 确保 dist 目录存在
const distDir = path.resolve(__dirname, 'dist');
if (!existsSync(distDir)) {
mkdirSync(distDir);
}
// 写入 sitemap.xml
writeFileSync(path.join(distDir, 'sitemap.xml'), sitemap);
console.log('Sitemap 生成成功!');
// 写入 robots.txt
writeFileSync(path.join(distDir, 'robots.txt'), robotsTxt);
console.log('Robots.txt 生成成功!');
}
},
Markdown({
wrapperComponent: 'article',
markdownItOptions: {
linkify: true,
highlight: function (str, lang) {
if (lang && hljs.getLanguage(lang)) {
try {
return hljs.highlight(str, { language: lang }).value;
} catch (__) { }
}
return ''; // use external default escaping
}
},
markdownItUses: [MarkdownItKatex, mermaidSSR, expandableMediaPlugin, blogInfoPlugin]
}),
minipic({
sharpOptions: {
webp: {
quality: 90,
},
png: {
quality: 80,
},
avif: {
quality: 80,
},
jpg: {
quality: 80,
},
jpeg: {
quality: 80,
},
gif: {
}
},
convert: [
{ from: 'png', to: 'webp' },
],
cache: true
})
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
},
},
server: {
host: '0.0.0.0',
}
})