207 lines
7.3 KiB
TypeScript
207 lines
7.3 KiB
TypeScript
import { defineConfig } from 'vitepress'
|
||
import fs from 'node:fs'
|
||
import path from 'node:path'
|
||
import type { HeadConfig, SiteConfig, TransformContext } from 'vitepress'
|
||
|
||
const siteUrl = process.env.SITE_URL || 'http://localhost:5173'
|
||
const siteName = '恭学教育集团'
|
||
const defaultOgImage = 'https://fenxiang-1304851894.cos.ap-nanjing.myqcloud.com/%E5%B0%81%E9%9D%A2.png'
|
||
const defaultKeywords = '天津专升本,专升本培训,恭学教育,天津专升本刷题,专升本网校,天津专升本教材,专升本辅导,天津专升本报名,专升本真题,天津专升本课程'
|
||
|
||
/**
|
||
* 将 Markdown 相对路径转换为站点 URL 路径
|
||
* - index.md -> /
|
||
* - books.md -> /books
|
||
* - knowledge/index.md -> /knowledge/
|
||
* - knowledge/sample-article.md -> /knowledge/sample-article
|
||
*/
|
||
function relativePathToUrl(relativePath: string): string {
|
||
let route = relativePath.replace(/\.md$/, '')
|
||
route = route.replace(/(^|\/)index$/, '')
|
||
if (!route.startsWith('/')) {
|
||
route = `/${route}`
|
||
}
|
||
return route || '/'
|
||
}
|
||
|
||
function formatDate(date: Date): string {
|
||
return date.toISOString().split('T')[0]
|
||
}
|
||
|
||
function getPageLastmod(relativePath: string): string | undefined {
|
||
const filePath = path.resolve('./docs', relativePath)
|
||
try {
|
||
const content = fs.readFileSync(filePath, 'utf-8')
|
||
const fmMatch = content.match(/^---\s*\n([\s\S]*?)\n---/)
|
||
if (fmMatch) {
|
||
const dateMatch = fmMatch[1].match(/^publishedAt:\s*(.+)$/m) || fmMatch[1].match(/^date:\s*(.+)$/m)
|
||
if (dateMatch) {
|
||
const d = new Date(dateMatch[1].trim())
|
||
if (!isNaN(d.getTime())) {
|
||
return formatDate(d)
|
||
}
|
||
}
|
||
}
|
||
const stat = fs.statSync(filePath)
|
||
return formatDate(stat.mtime)
|
||
} catch {
|
||
return undefined
|
||
}
|
||
}
|
||
|
||
export default defineConfig({
|
||
cleanUrls: 'with-subfolders',
|
||
title: '恭学教育集团',
|
||
titleTemplate: false,
|
||
description: '恭学教育集团是天津专升本培训领军品牌,专注天津专升本7年,已服务21万+学员。提供专业刷题系统、在线网校、权威教材和一对一升学规划,真题覆盖率100%,助你轻松升本成功!',
|
||
lang: 'zh-CN',
|
||
head: [
|
||
['link', { rel: 'icon', href: '/logo.png' }],
|
||
['link', { rel: 'apple-touch-icon', href: '/logo.png' }],
|
||
['meta', { name: 'author', content: '恭学教育集团' }],
|
||
['meta', { property: 'og:site_name', content: siteName }],
|
||
['meta', { property: 'og:locale', content: 'zh_CN' }],
|
||
['meta', { name: 'twitter:card', content: 'summary_large_image' }],
|
||
],
|
||
themeConfig: {
|
||
logo: '/logo.png',
|
||
nav: [],
|
||
outline: false,
|
||
socialLinks: [],
|
||
},
|
||
vite: {
|
||
resolve: {
|
||
alias: {
|
||
'@': '/docs/.vitepress',
|
||
},
|
||
},
|
||
plugins: [
|
||
{
|
||
name: 'knowledge-index-redirect',
|
||
configureServer(server) {
|
||
server.middlewares.use((req, res, next) => {
|
||
if (req.url === '/knowledge') {
|
||
res.statusCode = 302
|
||
res.setHeader('Location', '/knowledge/')
|
||
res.end()
|
||
return
|
||
}
|
||
next()
|
||
})
|
||
},
|
||
},
|
||
],
|
||
},
|
||
transformHead({ pageData, siteData }: TransformContext) {
|
||
const isNotFound = pageData.relativePath === '404.md'
|
||
const isArticle =
|
||
pageData.relativePath.startsWith('knowledge/') &&
|
||
pageData.relativePath !== 'knowledge/index.md' &&
|
||
pageData.frontmatter.publishedAt
|
||
|
||
const url = `${siteUrl}${relativePathToUrl(pageData.relativePath)}`
|
||
const title = pageData.title || siteName
|
||
const description = pageData.description || siteData.description || ''
|
||
const keywords = Array.isArray(pageData.frontmatter.keywords)
|
||
? pageData.frontmatter.keywords.join(',')
|
||
: defaultKeywords
|
||
const ogImage = pageData.frontmatter.coverImage || defaultOgImage
|
||
|
||
const tags: HeadConfig[] = [
|
||
['link', { rel: 'canonical', href: url }],
|
||
['meta', { name: 'robots', content: isNotFound ? 'noindex, nofollow' : 'index, follow' }],
|
||
['meta', { name: 'keywords', content: keywords }],
|
||
['meta', { property: 'og:title', content: title }],
|
||
['meta', { property: 'og:description', content: description }],
|
||
['meta', { property: 'og:url', content: url }],
|
||
['meta', { property: 'og:image', content: ogImage }],
|
||
['meta', { property: 'og:type', content: isArticle ? 'article' : 'website' }],
|
||
['meta', { name: 'twitter:title', content: title }],
|
||
['meta', { name: 'twitter:description', content: description }],
|
||
['meta', { name: 'twitter:image', content: ogImage }],
|
||
]
|
||
|
||
const organizationLd = {
|
||
'@context': 'https://schema.org',
|
||
'@type': 'Organization',
|
||
'@id': `${siteUrl}/#organization`,
|
||
name: siteName,
|
||
url: siteUrl,
|
||
logo: `${siteUrl}/logo.png`,
|
||
image: defaultOgImage,
|
||
description:
|
||
'恭学教育集团是天津专升本培训领军品牌,专注天津专升本培训、刷题系统、在线网校、权威教材和升学规划服务。',
|
||
sameAs: [],
|
||
}
|
||
|
||
const ldScripts: HeadConfig[] = [
|
||
['script', { type: 'application/ld+json' }, JSON.stringify(organizationLd)],
|
||
]
|
||
|
||
if (isArticle) {
|
||
const fm = pageData.frontmatter
|
||
const articleLd = {
|
||
'@context': 'https://schema.org',
|
||
'@type': 'Article',
|
||
headline: title,
|
||
description,
|
||
url,
|
||
image: ogImage,
|
||
author: {
|
||
'@type': fm.author ? 'Person' : 'Organization',
|
||
name: fm.author || siteName,
|
||
},
|
||
publisher: {
|
||
'@id': `${siteUrl}/#organization`,
|
||
},
|
||
datePublished: fm.publishedAt,
|
||
dateModified: fm.publishedAt,
|
||
keywords: Array.isArray(fm.tags) ? fm.tags.join(',') : keywords,
|
||
mainEntityOfPage: {
|
||
'@type': 'WebPage',
|
||
'@id': url,
|
||
},
|
||
}
|
||
ldScripts.push(['script', { type: 'application/ld+json' }, JSON.stringify(articleLd)])
|
||
} else {
|
||
const webPageLd = {
|
||
'@context': 'https://schema.org',
|
||
'@type': 'WebPage',
|
||
name: title,
|
||
description,
|
||
url,
|
||
isPartOf: {
|
||
'@id': `${siteUrl}/#organization`,
|
||
},
|
||
}
|
||
ldScripts.push(['script', { type: 'application/ld+json' }, JSON.stringify(webPageLd)])
|
||
}
|
||
|
||
return [...tags, ...ldScripts]
|
||
},
|
||
buildEnd(siteConfig: SiteConfig) {
|
||
const pages = siteConfig.pages.filter((p) => p !== '404.md')
|
||
const urls = pages
|
||
.map((p) => ({
|
||
loc: `${siteUrl}${relativePathToUrl(p)}`,
|
||
lastmod: getPageLastmod(p),
|
||
changefreq: p === 'index.md' ? 'daily' : 'weekly',
|
||
priority: p === 'index.md' ? '1.0' : '0.8',
|
||
}))
|
||
.sort((a, b) => a.loc.localeCompare(b.loc))
|
||
|
||
const sitemap = `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n${urls
|
||
.map(
|
||
(u) =>
|
||
` <url>\n <loc>${u.loc}</loc>\n${u.lastmod ? ` <lastmod>${u.lastmod}</lastmod>\n` : ''} <changefreq>${u.changefreq}</changefreq>\n <priority>${u.priority}</priority>\n </url>`,
|
||
)
|
||
.join('\n')}\n</urlset>\n`
|
||
|
||
fs.mkdirSync(siteConfig.outDir, { recursive: true })
|
||
fs.writeFileSync(path.join(siteConfig.outDir, 'sitemap.xml'), sitemap)
|
||
|
||
const robots = `User-agent: *\nAllow: /\nDisallow: /404\n\nSitemap: ${siteUrl}/sitemap.xml\n`
|
||
fs.writeFileSync(path.join(siteConfig.outDir, 'robots.txt'), robots)
|
||
},
|
||
})
|