147 lines
4.2 KiB
TypeScript
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',
|
|
}
|
|
})
|