diff --git a/package.json b/package.json index 846af18..56047dc 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "dependencies": { "@tailwindcss/typography": "^0.5.15", "@vite-pwa/vitepress": "^0.5.3", + "feed": "^4.2.2", "tailwindcss": "^3.4.14", "tsx": "^4.19.2", "vite-plugin-pwa": "^0.20.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 136f2e3..ae3b226 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@vite-pwa/vitepress': specifier: ^0.5.3 version: 0.5.3(vite-plugin-pwa@0.20.5(vite@5.4.10(@types/node@22.9.0)(terser@5.36.0))(workbox-build@7.1.1)(workbox-window@7.3.0)) + feed: + specifier: ^4.2.2 + version: 4.2.2 tailwindcss: specifier: ^3.4.14 version: 3.4.14 @@ -2243,6 +2246,10 @@ packages: picomatch: optional: true + feed@4.2.2: + resolution: {integrity: sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==} + engines: {node: '>=0.4.0'} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -3389,6 +3396,9 @@ packages: safe-regex@2.1.1: resolution: {integrity: sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==} + sax@1.4.1: + resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} + search-insights@2.15.0: resolution: {integrity: sha512-ch2sPCUDD4sbPQdknVl9ALSi9H7VyoeVbsxznYz6QV55jJ8CI3EtwpO1i84keN4+hF5IeHWIeGvc08530JkVXQ==} @@ -3956,6 +3966,10 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + xml-js@1.6.11: + resolution: {integrity: sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==} + hasBin: true + xml-name-validator@4.0.0: resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} engines: {node: '>=12'} @@ -6500,6 +6514,10 @@ snapshots: optionalDependencies: picomatch: 4.0.2 + feed@4.2.2: + dependencies: + xml-js: 1.6.11 + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -7900,6 +7918,8 @@ snapshots: dependencies: regexp-tree: 0.1.27 + sax@1.4.1: {} + search-insights@2.15.0: {} semver@5.7.2: {} @@ -8682,6 +8702,10 @@ snapshots: wrappy@1.0.2: {} + xml-js@1.6.11: + dependencies: + sax: 1.4.1 + xml-name-validator@4.0.0: {} yallist@3.1.1: {} diff --git a/src/.vitepress/config.ts b/src/.vitepress/config.ts index d968be6..2984e07 100644 --- a/src/.vitepress/config.ts +++ b/src/.vitepress/config.ts @@ -1,5 +1,6 @@ -import { defineConfigWithTheme, createContentLoader } from 'vitepress' +import { defineConfigWithTheme } from 'vitepress' import { withPwa } from '@vite-pwa/vitepress' +import { genFeed } from './genFeed.js' interface ThemeConfig { postsPerPage?: number @@ -114,5 +115,6 @@ export default withPwa( }, }, themeConfig: themeConfig, + buildEnd: genFeed, }) ) diff --git a/src/.vitepress/genFeed.ts b/src/.vitepress/genFeed.ts new file mode 100644 index 0000000..7c794c8 --- /dev/null +++ b/src/.vitepress/genFeed.ts @@ -0,0 +1,55 @@ +import path from 'path' +import { writeFileSync } from 'fs' +import { Feed } from 'feed' +import { createContentLoader, type SiteConfig } from 'vitepress' + +const baseUrl = `https://pfcc.blog` + +export async function genFeed(config: SiteConfig) { + const feed = new Feed({ + title: '飞桨开源社区博客', + description: 'Wonderful stories from PaddlePaddle contributors', + id: baseUrl, + link: baseUrl, + language: 'zh-CN', + image: 'https://pfcc.blog/logo.png', + favicon: `${baseUrl}/favicon.ico`, + copyright: 'Copyright (c) 2023-present, PaddlePaddle contributors', + }) + + const posts = await createContentLoader('posts/*.md', { + excerpt: true, + render: true, + }).load() + + posts.sort( + (a, b) => +new Date(b.frontmatter.date as string) - +new Date(a.frontmatter.date as string) + ) + + const formatAuthor = (author: { + name: string + github?: string + }): { name: string; link?: string } => { + return { + name: author.name, + link: author.github ? `https://github.com/${author.github}` : undefined, + } + } + + for (const { url, excerpt, frontmatter, html } of posts) { + feed.addItem({ + title: frontmatter.title, + id: `${baseUrl}${url}`, + link: `${baseUrl}${url}`, + description: excerpt, + content: html?.replaceAll('​', ''), + author: [ + formatAuthor(frontmatter.author), + ...(frontmatter.co_authors?.map(formatAuthor) ?? []), + ], + date: new Date(frontmatter.date as string), + }) + } + + writeFileSync(path.join(config.outDir, 'feed.rss'), feed.rss2()) +}