feat: 动态sitemap.xml

This commit is contained in:
2026-08-14 23:55:52 +08:00
parent d7bbb7b70b
commit e4c362030d
9 changed files with 99 additions and 61 deletions

View File

@@ -2,7 +2,6 @@
import {defineConfig} from 'astro/config'; import {defineConfig} from 'astro/config';
import solidJs from '@astrojs/solid-js'; import solidJs from '@astrojs/solid-js';
import node from '@astrojs/node'; import node from '@astrojs/node';
import sitemap from "@astrojs/sitemap";
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
@@ -11,11 +10,7 @@ export default defineConfig({
server: { server: {
host: "0.0.0.0", host: "0.0.0.0",
}, },
integrations: [solidJs(), sitemap({ integrations: [solidJs()],
filter: (page) => {
return !page.includes('/embed/');
}
})],
adapter: node({ adapter: node({
mode: 'standalone' mode: 'standalone'
}), }),

View File

@@ -11,7 +11,6 @@
}, },
"dependencies": { "dependencies": {
"@astrojs/node": "11.0.2", "@astrojs/node": "11.0.2",
"@astrojs/sitemap": "^3.7.3",
"@astrojs/solid-js": "^5.1.3", "@astrojs/solid-js": "^5.1.3",
"astro": "^7.0.6", "astro": "^7.0.6",
"dayjs": "^1.11.21", "dayjs": "^1.11.21",

53
pnpm-lock.yaml generated
View File

@@ -11,9 +11,6 @@ importers:
'@astrojs/node': '@astrojs/node':
specifier: 11.0.2 specifier: 11.0.2
version: 11.0.2(astro@7.0.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(rollup@4.62.2)) version: 11.0.2(astro@7.0.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(rollup@4.62.2))
'@astrojs/sitemap':
specifier: ^3.7.3
version: 3.7.3
'@astrojs/solid-js': '@astrojs/solid-js':
specifier: ^5.1.3 specifier: ^5.1.3
version: 5.1.3(@types/node@26.1.0)(lightningcss@1.32.0)(solid-js@1.9.14) version: 5.1.3(@types/node@26.1.0)(lightningcss@1.32.0)(solid-js@1.9.14)
@@ -146,9 +143,6 @@ packages:
resolution: {integrity: sha512-KTivpmnz6lDsC6o9H4+DNm2SrE/GHzw8cNAvEJwAvUT+eoaEnn/4NtbDNfRRaxaJHdp15gf+tfHAWiXR4wB3BA==} resolution: {integrity: sha512-KTivpmnz6lDsC6o9H4+DNm2SrE/GHzw8cNAvEJwAvUT+eoaEnn/4NtbDNfRRaxaJHdp15gf+tfHAWiXR4wB3BA==}
engines: {node: '>=22.12.0'} engines: {node: '>=22.12.0'}
'@astrojs/sitemap@3.7.3':
resolution: {integrity: sha512-f8euLVsyeAmAkSm/1M2Kb8sL8byQmfgbvBNaHFItCheTj/IpiJYSEWVcqDHZ/yEHxiS7+w87mQkzwZaPHmk5GA==}
'@astrojs/solid-js@5.1.3': '@astrojs/solid-js@5.1.3':
resolution: {integrity: sha512-KxfYt4y1d7BuSw6EsN1EaPoGYsIES7bEI6AtTbncuabRUUMZs+mOWOeOdmgnwVLj+jbNbhBjUZsqr77eUviZdw==} resolution: {integrity: sha512-KxfYt4y1d7BuSw6EsN1EaPoGYsIES7bEI6AtTbncuabRUUMZs+mOWOeOdmgnwVLj+jbNbhBjUZsqr77eUviZdw==}
engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0} engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0}
@@ -1177,15 +1171,9 @@ packages:
'@types/nlcst@2.0.3': '@types/nlcst@2.0.3':
resolution: {integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==} resolution: {integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==}
'@types/node@24.13.2':
resolution: {integrity: sha512-fRa09kZTgu8o71KFcDjUFuc7F+dEbZYZmkI0mg5YBTRs0yMKjYHsq/c0urDKeDb+D5qVgXOdFcuu+DZPKOITwA==}
'@types/node@26.1.0': '@types/node@26.1.0':
resolution: {integrity: sha512-O0A1G3xPGy4w7AgQdAQYUlQ+BKk2Oovw8eRpofyp5KdBZULnbe+WqaOVNrm705SHphCiG4XHsACrSmPu1f+Kgw==} resolution: {integrity: sha512-O0A1G3xPGy4w7AgQdAQYUlQ+BKk2Oovw8eRpofyp5KdBZULnbe+WqaOVNrm705SHphCiG4XHsACrSmPu1f+Kgw==}
'@types/sax@1.2.7':
resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==}
'@types/tough-cookie@4.0.5': '@types/tough-cookie@4.0.5':
resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==}
@@ -1203,9 +1191,6 @@ packages:
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
arg@5.0.2:
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
argparse@2.0.1: argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
@@ -1937,11 +1922,6 @@ packages:
sisteransi@1.0.5: sisteransi@1.0.5:
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
sitemap@9.0.1:
resolution: {integrity: sha512-S6hzjGJSG3d6if0YoF5kTyeRJvia6FSTBroE5fQ0bu1QNxyJqhhinfUsXi9fH3MgtXODWvwo2BDyQSnhPQ88uQ==}
engines: {node: '>=20.19.5', npm: '>=10.8.2'}
hasBin: true
smol-toml@1.7.0: smol-toml@1.7.0:
resolution: {integrity: sha512-aqVvWoyO21L23mb+drl4RmMXbf6N7FdHjAhTRA9ZBL7apWBgfWC16KjrASI+1p9GAroljyMHj6fK67i0UiTNvQ==} resolution: {integrity: sha512-aqVvWoyO21L23mb+drl4RmMXbf6N7FdHjAhTRA9ZBL7apWBgfWC16KjrASI+1p9GAroljyMHj6fK67i0UiTNvQ==}
engines: {node: '>= 18'} engines: {node: '>= 18'}
@@ -1965,9 +1945,6 @@ packages:
resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
stream-replace-string@2.0.0:
resolution: {integrity: sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==}
stringify-entities@4.0.4: stringify-entities@4.0.4:
resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
@@ -2031,9 +2008,6 @@ packages:
uncrypto@0.1.3: uncrypto@0.1.3:
resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==}
undici-types@7.18.2:
resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}
undici-types@7.28.0: undici-types@7.28.0:
resolution: {integrity: sha512-LJAfY+2w6HGeT8d8J1wNQsUGUEGio6NWWpwdwurQe4f6oojzCFuGLizl1KSve4irsTxyLly1QhEeE6iapdaIvQ==} resolution: {integrity: sha512-LJAfY+2w6HGeT8d8J1wNQsUGUEGio6NWWpwdwurQe4f6oojzCFuGLizl1KSve4irsTxyLly1QhEeE6iapdaIvQ==}
@@ -2394,12 +2368,6 @@ snapshots:
dependencies: dependencies:
prismjs: 1.30.0 prismjs: 1.30.0
'@astrojs/sitemap@3.7.3':
dependencies:
sitemap: 9.0.1
stream-replace-string: 2.0.0
zod: 4.4.3
'@astrojs/solid-js@5.1.3(@types/node@26.1.0)(lightningcss@1.32.0)(solid-js@1.9.14)': '@astrojs/solid-js@5.1.3(@types/node@26.1.0)(lightningcss@1.32.0)(solid-js@1.9.14)':
dependencies: dependencies:
solid-js: 1.9.14 solid-js: 1.9.14
@@ -3162,18 +3130,10 @@ snapshots:
dependencies: dependencies:
'@types/unist': 3.0.3 '@types/unist': 3.0.3
'@types/node@24.13.2':
dependencies:
undici-types: 7.18.2
'@types/node@26.1.0': '@types/node@26.1.0':
dependencies: dependencies:
undici-types: 8.3.0 undici-types: 8.3.0
'@types/sax@1.2.7':
dependencies:
'@types/node': 26.1.0
'@types/tough-cookie@4.0.5': {} '@types/tough-cookie@4.0.5': {}
'@types/unist@3.0.3': {} '@types/unist@3.0.3': {}
@@ -3189,8 +3149,6 @@ snapshots:
normalize-path: 3.0.0 normalize-path: 3.0.0
picomatch: 2.3.2 picomatch: 2.3.2
arg@5.0.2: {}
argparse@2.0.1: {} argparse@2.0.1: {}
aria-query@5.3.2: {} aria-query@5.3.2: {}
@@ -4050,13 +4008,6 @@ snapshots:
sisteransi@1.0.5: {} sisteransi@1.0.5: {}
sitemap@9.0.1:
dependencies:
'@types/node': 24.13.2
'@types/sax': 1.2.7
arg: 5.0.2
sax: 1.6.0
smol-toml@1.7.0: {} smol-toml@1.7.0: {}
solid-js@1.9.14: solid-js@1.9.14:
@@ -4080,8 +4031,6 @@ snapshots:
statuses@2.0.2: {} statuses@2.0.2: {}
stream-replace-string@2.0.0: {}
stringify-entities@4.0.4: stringify-entities@4.0.4:
dependencies: dependencies:
character-entities-html4: 2.1.0 character-entities-html4: 2.1.0
@@ -4139,8 +4088,6 @@ snapshots:
uncrypto@0.1.3: {} uncrypto@0.1.3: {}
undici-types@7.18.2: {}
undici-types@7.28.0: {} undici-types@7.28.0: {}
undici-types@8.3.0: {} undici-types@8.3.0: {}

View File

@@ -1,2 +1,4 @@
User-agent: * User-agent: *
Allow: / Allow: /
Sitemap: https://ua42.com/sitemap-index.xml

View File

@@ -1,5 +1,5 @@
export const metadata = { export const metadata = {
site: "https://ua42.com",
siteTitle: "Uroboros", siteTitle: "Uroboros",
postPageSize: 6 postPageSize: 6
} }

View File

@@ -0,0 +1,33 @@
import type {APIRoute} from 'astro';
import {metadata} from "@/consts";
const site = metadata.site
const staticUrls = [
'',
'/archives',
'/search',
];
export const GET: APIRoute = async () => {
const urls = staticUrls
.filter((url, index, array) => {
return array.indexOf(url) === index;
});
const xml = `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urls.map((url) => `<url>
<loc>${site}${url}</loc>
</url>`
)
.join('\n')}
</urlset>`;
return new Response(xml, {
status: 200,
headers: {
'Content-Type': 'application/xml; charset=utf-8',
'Cache-Control': 'public, max-age=3600, s-maxage=3600',
},
});
};

View File

@@ -0,0 +1,35 @@
import type {APIRoute} from 'astro';
import {metadata} from "@/consts";
import {createHttp} from "@/lib/request.ts";
import type {PostForSitemap} from "@/types";
import dayjs from "dayjs";
const site = metadata.site
export const GET: APIRoute = async (context) => {
const http = createHttp(context.request.headers);
const {data} = await http.get<ApiResponse<PostForSitemap[]>>("posts/sitemap")
const urls = data
.filter((url, index, array) => {
return array.indexOf(url) === index;
});
const xml = `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urls.map((post) => `<url>
<loc>${site}/${post.slug}</loc>
<lastmod>${dayjs(post.updated_at || post.created_at).toISOString()}</lastmod>
</url>`
)
.join('\n')}
</urlset>`;
return new Response(xml, {
status: 200,
headers: {
'Content-Type': 'application/xml; charset=utf-8',
'Cache-Control': 'public, max-age=3600, s-maxage=3600',
},
});
};

21
src/pages/sitemap.xml.ts Normal file
View File

@@ -0,0 +1,21 @@
import type {APIRoute} from 'astro';
import {metadata} from "@/consts";
const site = metadata.site
export const GET: APIRoute = () => {
const xml = `<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap>
<loc>${site}/sitemap-pages.xml</loc>
</sitemap>
<sitemap>
<loc>${site}/sitemap-posts.xml</loc>
</sitemap>
</sitemapindex>`;
return new Response(xml, {
headers: {
'Content-Type': 'application/xml; charset=utf-8',
},
});
};

View File

@@ -24,3 +24,9 @@ export type CategoriesStats = {
code: string code: string
post_count: number; post_count: number;
} }
export type PostForSitemap = {
slug: string
created_at: string
updated_at: string
}