feat: tntegrated @nolebase/vitepress-plugin-meta for SEO and meta elements (#374)
部署文档 / build (push) Has been cancelled Details

Signed-off-by: Neko Ayaka <neko@ayaka.moe>
pull/375/head
Neko Ayaka 2024-07-08 23:14:40 +08:00 committed by GitHub
parent 63ee8492eb
commit dadd466a6b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 722 additions and 192 deletions

11
.vscode/settings.json vendored
View File

@ -1,20 +1,9 @@
{ {
"cSpell.words": [
"antfu",
"astro",
"Attributify",
"iconify",
"katex",
"pangu",
"pjts"
],
"editor.formatOnSave": false, "editor.formatOnSave": false,
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit", "source.fixAll.eslint": "explicit",
"source.organizeImports": "never" "source.organizeImports": "never"
}, },
// Enable the ESlint flat config support
"eslint.experimental.useFlatConfig": true,
// The following is optional. // The following is optional.
// It's better to put under project setting `.vscode/settings.json` // It's better to put under project setting `.vscode/settings.json`
// to avoid conflicts with working with different eslint configs // to avoid conflicts with working with different eslint configs

19
cspell.config.yaml 100644
View File

@ -0,0 +1,19 @@
version: "0.2"
ignorePaths: []
dictionaryDefinitions: []
dictionaries: []
words:
- antfu
- astro
- Attributify
- iconify
- katex
- nolebase
- octicon
- pangu
- pjts
- unocss
- unplugin
- vitepress
ignoreWords: []
import: []

View File

@ -16,6 +16,8 @@
"devDependencies": { "devDependencies": {
"@antfu/eslint-config": "^2.21.1", "@antfu/eslint-config": "^2.21.1",
"@cloudflare/workers-types": "^4.20240620.0", "@cloudflare/workers-types": "^4.20240620.0",
"@iconify-json/carbon": "^1.1.36",
"@iconify-json/icon-park-outline": "^1.1.15",
"@iconify-json/octicon": "^1.1.55", "@iconify-json/octicon": "^1.1.55",
"@project-trans/suggestion-box": "^0.0.9", "@project-trans/suggestion-box": "^0.0.9",
"@project-trans/vitepress-theme-project-trans": "workspace:*", "@project-trans/vitepress-theme-project-trans": "workspace:*",

View File

@ -41,9 +41,10 @@
"@antfu/eslint-config": "^2.21.1", "@antfu/eslint-config": "^2.21.1",
"@cloudflare/workers-types": "^4.20240620.0", "@cloudflare/workers-types": "^4.20240620.0",
"@iconify-json/octicon": "^1.1.55", "@iconify-json/octicon": "^1.1.55",
"@nolebase/vitepress-plugin-enhanced-readabilities": "2.1.2", "@nolebase/vitepress-plugin-enhanced-readabilities": "^2.1.2",
"@nolebase/vitepress-plugin-git-changelog": "2.1.2", "@nolebase/vitepress-plugin-git-changelog": "^2.1.2",
"@nolebase/vitepress-plugin-highlight-targeted-heading": "2.1.2", "@nolebase/vitepress-plugin-highlight-targeted-heading": "^2.1.2",
"@nolebase/vitepress-plugin-meta": "^2.2.1",
"@project-trans/suggestion-box": "^0.0.9", "@project-trans/suggestion-box": "^0.0.9",
"@types/markdown-it": "^14.1.1", "@types/markdown-it": "^14.1.1",
"@types/markdown-it-footnote": "^3.0.4", "@types/markdown-it-footnote": "^3.0.4",

View File

@ -2,6 +2,7 @@ import { readFileSync, statSync } from 'node:fs'
import { dirname, join, resolve } from 'node:path' import { dirname, join, resolve } from 'node:path'
import { fileURLToPath } from 'node:url' import { fileURLToPath } from 'node:url'
import { GitChangelog } from '@nolebase/vitepress-plugin-git-changelog/vite' import { GitChangelog } from '@nolebase/vitepress-plugin-git-changelog/vite'
import { transformHeadMeta } from '@nolebase/vitepress-plugin-meta'
import { import {
MarkdownSectionWrapper, MarkdownSectionWrapper,
PageHeaderTemplate, PageHeaderTemplate,
@ -19,7 +20,7 @@ import { useThemeContext } from './utils/themeContext'
// https://vitepress.dev/reference/site-config // https://vitepress.dev/reference/site-config
function genConfig() { function genConfig() {
const themeConfig = useThemeContext() const themeConfig = useThemeContext()
const { siteTitle, siteDescription, githubRepoLink, rootDir, nav } const { siteTitle, githubRepoLink, nav }
= themeConfig = themeConfig
return defineConfig({ return defineConfig({
lang: 'zh-CN', lang: 'zh-CN',
@ -122,143 +123,12 @@ function genConfig() {
}, },
}, },
}, },
transformHead: (context) => { transformHead: async (context) => {
const head = [...context.head] || [] let head = [...context.head]
const pageSourceFilePath = join(rootDir, context.pageData.filePath) const returnedHead = await transformHeadMeta()(head, context)
const pageSourceFileStat = statSync( if (typeof returnedHead !== 'undefined')
join(rootDir, context.pageData.filePath), head = returnedHead
)
if (pageSourceFileStat.isDirectory()) {
head.push([
'meta',
{
property: 'og:title',
content: siteTitle,
},
])
head.push([
'meta',
{
name: 'description',
content: siteDescription,
},
])
return head
}
let pageSourceFileContent = readFileSync(pageSourceFilePath, {
encoding: 'utf-8',
})
// remove all frontmatter
pageSourceFileContent = pageSourceFileContent.replace(
/---[\s\S]*?---/,
'',
)
// remove markdown heading markup but keep the text content
pageSourceFileContent = pageSourceFileContent.replace(
/^(#+)\s+(.*)/gm,
' $2 ',
)
// remove markdown link markup but keep the text content
pageSourceFileContent = pageSourceFileContent.replace(
/\[([^\]]+)\]\([^)]+\)/gm,
' $1 ',
)
// remove markdown image markup but keep the text content
pageSourceFileContent = pageSourceFileContent.replace(
/\!\[([^\]]+)\]\([^)]+\)/gm,
' $1 ',
)
// remove markdown reference link markup but keep the text content
pageSourceFileContent = pageSourceFileContent.replace(/\[.*]/gm, '')
// remove markdown bold markup but keep the text content
pageSourceFileContent = pageSourceFileContent.replace(
/\*\*([^*]+)\*\*/gm,
' $1 ',
)
pageSourceFileContent = pageSourceFileContent.replace(
/__([^*]+)__/gm,
' $1 ',
)
// remove markdown italic markup but keep the text content
pageSourceFileContent = pageSourceFileContent.replace(
/\*([^*]+)\*/gm,
' $1 ',
)
pageSourceFileContent = pageSourceFileContent.replace(
/_([^*]+)_/gm,
' $1 ',
)
// remove markdown code markup but keep the text content
pageSourceFileContent = pageSourceFileContent.replace(
/`([^`]+)`/gm,
' $1 ',
)
// remove markdown code block markup but keep the text content
pageSourceFileContent = pageSourceFileContent.replace(
/```([^`]+)```/gm,
' $1 ',
)
// remove markdown table header markup but keep the text content
pageSourceFileContent = pageSourceFileContent.replace(/\|:?-+:?\|/gm, '')
// remove markdown table cell markup but keep the text content
pageSourceFileContent = pageSourceFileContent.replace(
/\|([^|]+)\|/gm,
' $1 ',
)
// remove specific html tags completely
const tags = ['']
tags.forEach((tag) => {
pageSourceFileContent = pageSourceFileContent.replace(
new RegExp(`<${tag}[^>]*>[\\s\\S]*?<\\/${tag}>`, 'g'),
'',
)
})
// remove specific html tags but keep the text content
const tagsToKeepContent = ['u', 'Containers', 'img', 'a']
tagsToKeepContent.forEach((tag) => {
pageSourceFileContent = pageSourceFileContent.replace(
new RegExp(`<${tag}[^>]*>([\\s\\S]*?)<\\/${tag}>`, 'g'),
' $1 ',
)
})
// remove all new lines (either \r, \n)
pageSourceFileContent = pageSourceFileContent.replace(/[\r|\n]/gm, '')
// calculate the first 200 characters of the page content
let pageContent = pageSourceFileContent.slice(0, 200)
// trim space
pageContent = pageContent.trim()
// if pageSourceFileContent is longer than 200 characters, add ellipsis
if (pageSourceFileContent.length > 100)
pageContent += '...'
if (context.pageData.frontmatter?.layout === 'home') {
pageContent
= context.pageData.frontmatter?.hero?.tagline ?? siteDescription
}
head.push(['meta', { name: 'description', content: pageContent }])
head.push(['meta', { property: 'og:title', content: context.title }])
head.push(['meta', { property: 'og:description', content: pageContent }])
head.push(['meta', { property: 'og:title', content: context.title }])
head.push([
'meta',
{ property: 'twitter:description', content: pageContent },
])
return head return head
}, },

File diff suppressed because it is too large Load Diff