From 524f8106508be20a2233ad6ef36fc16a840127d7 Mon Sep 17 00:00:00 2001 From: Mehdi M Date: Sun, 19 Nov 2023 13:07:49 +0100 Subject: [PATCH 01/12] Arrange base feed code before adding more --- vitepress/.vitepress/rss.mjs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/vitepress/.vitepress/rss.mjs b/vitepress/.vitepress/rss.mjs index 8ce57a8..cf28f57 100644 --- a/vitepress/.vitepress/rss.mjs +++ b/vitepress/.vitepress/rss.mjs @@ -9,14 +9,22 @@ const APP_URL = `https://blog.mehdi.cc` /** @param {import('vitepress').SiteConfig} config */ export async function rss(config) { + const content = (await createContentLoader(['articles/*.md', 'notes/*.md'], { excerpt: true, render: true }).load()) + .filter(isPublished) + .toSorted(comparePublicationDate) + + /** + * FULL CONTENT + */ + /** * https://www.rssboard.org/rss-profile * https://github.com/jpmonette/feed */ - const feed = new Feed({ + const feedWithEverything = new Feed({ docs: 'https://www.rssboard.org/rss-specification', - link: APP_URL + 'link', - title: config.site.title, + link: APP_URL, + title: 'Mehdi’s notes and articles', description: config.site.description, language: config.site.lang, // image: 'https://blog.mehdi.cc/file.png', @@ -26,11 +34,9 @@ export async function rss(config) { ttl: 2880, // 1 day, }); - (await createContentLoader(['articles/*.md', 'notes/*.md'], { excerpt: true, render: true }).load()) - .filter(isPublished) - .toSorted(comparePublicationDate) + content .forEach(({ url, excerpt, frontmatter, html }) => - feed.addItem({ + feedWithEverything.addItem({ title: frontmatter.title, id: `${APP_URL}${url}`, link: `${APP_URL}${url}`, @@ -40,10 +46,10 @@ export async function rss(config) { author: [{ name: 'Mehdi Merah', link: 'https://mehdi.cc', - email: ' ', // hack, otherwise is missing in RSS + email: 'hi@mehdi.cc', }], }) ) - writeFileSync(path.join(config.outDir, 'feed.xml'), feed.rss2()) + writeFileSync(path.join(config.outDir, 'feed.xml'), feedWithEverything.rss2()) } From 7a7031c3156d95d02a9cfb22bfff477e73a45e0e Mon Sep 17 00:00:00 2001 From: Mehdi M Date: Sun, 19 Nov 2023 13:08:26 +0100 Subject: [PATCH 02/12] Add separate feeds for notes and articles --- vitepress/.vitepress/rss.mjs | 83 ++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/vitepress/.vitepress/rss.mjs b/vitepress/.vitepress/rss.mjs index cf28f57..a8f1924 100644 --- a/vitepress/.vitepress/rss.mjs +++ b/vitepress/.vitepress/rss.mjs @@ -7,6 +7,15 @@ import { comparePublicationDate, isPublished } from './utils/frontmatter.mjs' /** @todo: should come from .env */ const APP_URL = `https://blog.mehdi.cc` +/** + * @param {import('vitepress').ContentData} content + * @param {string} type + */ +const isContentType = (content, type) => content.url.startsWith(`/${type}s/`) + +const isArticle = content => isContentType(content, 'article') +const isNote = content => isContentType(content, 'note') + /** @param {import('vitepress').SiteConfig} config */ export async function rss(config) { const content = (await createContentLoader(['articles/*.md', 'notes/*.md'], { excerpt: true, render: true }).load()) @@ -52,4 +61,78 @@ export async function rss(config) { ) writeFileSync(path.join(config.outDir, 'feed.xml'), feedWithEverything.rss2()) + + /** + * NOTES ONLY + */ + + const feedWithNotesOnly = new Feed({ + docs: 'https://www.rssboard.org/rss-specification', + link: APP_URL, + title: 'Mehdi’s notes', + description: 'A chronological gathering of… notes.', + language: config.site.lang, + // image: 'https://blog.mehdi.cc/file.png', + // favicon: `${APP_URL}/favicon.ico`, + copyright: 'Copyright © 2023-present, Mehdi Merah', + feed: `${APP_URL}/feed-notes-only.xml`, + ttl: 2880, // 1 day, + }); + + content + .filter(isNote) + .forEach(({ url, excerpt, frontmatter, html }) => + feedWithNotesOnly.addItem({ + title: frontmatter.title, + id: `${APP_URL}${url}`, + link: `${APP_URL}${url}`, + description: frontmatter.description || excerpt, + content: html, + date: frontmatter.publishedAt, + author: [{ + name: 'Mehdi Merah', + link: 'https://mehdi.cc', + email: 'hi@mehdi.cc', + }], + }) + ) + + writeFileSync(path.join(config.outDir, 'feed-notes-only.xml'), feedWithNotesOnly.rss2()) + + /** + * ARTICLES ONLY + */ + + const feedWithArticlesOnly = new Feed({ + docs: 'https://www.rssboard.org/rss-specification', + link: APP_URL, + title: 'Mehdi’s articles', + description: 'A chronological gathering of… articles.', + language: config.site.lang, + // image: 'https://blog.mehdi.cc/file.png', + // favicon: `${APP_URL}/favicon.ico`, + copyright: 'Copyright © 2023-present, Mehdi Merah', + feed: `${APP_URL}/feed-articles-only.xml`, + ttl: 2880, // 1 day, + }); + + content + .filter(isArticle) + .forEach(({ url, excerpt, frontmatter, html }) => + feedWithArticlesOnly.addItem({ + title: frontmatter.title, + id: `${APP_URL}${url}`, + link: `${APP_URL}${url}`, + description: frontmatter.description || excerpt, + content: html, + date: frontmatter.publishedAt, + author: [{ + name: 'Mehdi Merah', + link: 'https://mehdi.cc', + email: 'hi@mehdi.cc', + }], + }) + ) + + writeFileSync(path.join(config.outDir, 'feed-articles-only.xml'), feedWithArticlesOnly.rss2()) } From 2f66ff1f7aeef7bb99160c09ba787255ecd78d75 Mon Sep 17 00:00:00 2001 From: Mehdi M Date: Sun, 19 Nov 2023 13:15:51 +0100 Subject: [PATCH 03/12] Type-hint RSS feed script --- vitepress/.vitepress/rss.mjs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/vitepress/.vitepress/rss.mjs b/vitepress/.vitepress/rss.mjs index a8f1924..afc9c39 100644 --- a/vitepress/.vitepress/rss.mjs +++ b/vitepress/.vitepress/rss.mjs @@ -4,20 +4,27 @@ import { Feed } from 'feed' import { createContentLoader } from 'vitepress' import { comparePublicationDate, isPublished } from './utils/frontmatter.mjs' +/** @typedef {import('vitepress').ContentData} ContentData */ + /** @todo: should come from .env */ const APP_URL = `https://blog.mehdi.cc` /** - * @param {import('vitepress').ContentData} content + * @param {ContentData} content * @param {string} type */ -const isContentType = (content, type) => content.url.startsWith(`/${type}s/`) +const isContentType = ({ url }, type) => url.startsWith(`/${type}s/`) +/** @param {ContentData} content */ const isArticle = content => isContentType(content, 'article') + +/** @param {ContentData} content */ const isNote = content => isContentType(content, 'note') /** @param {import('vitepress').SiteConfig} config */ export async function rss(config) { + + /** @type {ContentData[]} */ const content = (await createContentLoader(['articles/*.md', 'notes/*.md'], { excerpt: true, render: true }).load()) .filter(isPublished) .toSorted(comparePublicationDate) From a140347574127f62f7a987b154823b2dc892d313 Mon Sep 17 00:00:00 2001 From: Mehdi M Date: Sun, 19 Nov 2023 13:16:04 +0100 Subject: [PATCH 04/12] Add feed with articles excerpt only --- vitepress/.vitepress/rss.mjs | 37 ++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/vitepress/.vitepress/rss.mjs b/vitepress/.vitepress/rss.mjs index afc9c39..158dc35 100644 --- a/vitepress/.vitepress/rss.mjs +++ b/vitepress/.vitepress/rss.mjs @@ -142,4 +142,41 @@ export async function rss(config) { ) writeFileSync(path.join(config.outDir, 'feed-articles-only.xml'), feedWithArticlesOnly.rss2()) + + /** + * ARTICLES EXCERPTS ONLY + */ + + const feedWithArticlesExcerptOnly = new Feed({ + docs: 'https://www.rssboard.org/rss-specification', + link: APP_URL, + title: 'Mehdi’s articles', + description: 'Excerpt of my articles.', + language: config.site.lang, + // image: 'https://blog.mehdi.cc/file.png', + // favicon: `${APP_URL}/favicon.ico`, + copyright: 'Copyright © 2023-present, Mehdi Merah', + feed: `${APP_URL}/feed-articles-excerpts-only.xml`, + ttl: 2880, // 1 day, + }); + + content + .filter(isArticle) + .forEach(({ url, excerpt, frontmatter, html }) => + feedWithArticlesExcerptOnly.addItem({ + title: frontmatter.title, + id: `${APP_URL}${url}`, + link: `${APP_URL}${url}`, + description: frontmatter.description || excerpt, + content: excerpt, + date: frontmatter.publishedAt, + author: [{ + name: 'Mehdi Merah', + link: 'https://mehdi.cc', + email: 'hi@mehdi.cc', + }], + }) + ) + + writeFileSync(path.join(config.outDir, 'feed-articles-excerpts-only.xml'), feedWithArticlesExcerptOnly.rss2()) } From 4ad7734a2fa90e114ff5ace680810745e901dca8 Mon Sep 17 00:00:00 2001 From: Mehdi M Date: Sun, 19 Nov 2023 13:20:15 +0100 Subject: [PATCH 05/12] Add feed with articles excerpts and notes --- vitepress/.vitepress/rss.mjs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/vitepress/.vitepress/rss.mjs b/vitepress/.vitepress/rss.mjs index 158dc35..8350ef7 100644 --- a/vitepress/.vitepress/rss.mjs +++ b/vitepress/.vitepress/rss.mjs @@ -179,4 +179,40 @@ export async function rss(config) { ) writeFileSync(path.join(config.outDir, 'feed-articles-excerpts-only.xml'), feedWithArticlesExcerptOnly.rss2()) + + /** + * ARTICLES EXCERPTS + NOTES + */ + + const feedWithNotesAndArticlesExcerpts = new Feed({ + docs: 'https://www.rssboard.org/rss-specification', + link: APP_URL, + title: 'Mehdi’s light feed', + description: 'Articles excerpts and notes.', + language: config.site.lang, + // image: 'https://blog.mehdi.cc/file.png', + // favicon: `${APP_URL}/favicon.ico`, + copyright: 'Copyright © 2023-present, Mehdi Merah', + feed: `${APP_URL}/feed-articles-excerpts-and-notes.xml`, + ttl: 2880, // 1 day, + }); + + content + .forEach(({ url, excerpt, frontmatter, html }) => + feedWithNotesAndArticlesExcerpts.addItem({ + title: frontmatter.title, + id: `${APP_URL}${url}`, + link: `${APP_URL}${url}`, + description: frontmatter.description || excerpt, + content: isNote({ url }) ? html : excerpt, + date: frontmatter.publishedAt, + author: [{ + name: 'Mehdi Merah', + link: 'https://mehdi.cc', + email: 'hi@mehdi.cc', + }], + }) + ) + + writeFileSync(path.join(config.outDir, 'feed-articles-excerpts-and-notes.xml'), feedWithNotesAndArticlesExcerpts.rss2()) } From 34fc83b44e276622cc5ccd93007b16809f08dde0 Mon Sep 17 00:00:00 2001 From: Mehdi M Date: Sun, 19 Nov 2023 13:21:55 +0100 Subject: [PATCH 06/12] Add new feeds to `size-limit` --- .size-limit.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.size-limit.json b/.size-limit.json index 3583993..9018ce4 100644 --- a/.size-limit.json +++ b/.size-limit.json @@ -29,6 +29,6 @@ }, { "name": "Feeds", - "path": ["public/feed.xml"] + "path": ["public/feed.xml", "public/feed-*.xml"] } ] From b5a558dbdc96160a4fc18e26b659799d7ddd638e Mon Sep 17 00:00:00 2001 From: Mehdi M Date: Sun, 19 Nov 2023 14:14:59 +0100 Subject: [PATCH 07/12] Extract content type utils --- vitepress/.vitepress/rss.mjs | 13 +----------- vitepress/.vitepress/utils/content-type.mjs | 23 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 12 deletions(-) create mode 100644 vitepress/.vitepress/utils/content-type.mjs diff --git a/vitepress/.vitepress/rss.mjs b/vitepress/.vitepress/rss.mjs index 8350ef7..1ae0532 100644 --- a/vitepress/.vitepress/rss.mjs +++ b/vitepress/.vitepress/rss.mjs @@ -2,6 +2,7 @@ import path from 'path' import { writeFileSync } from 'fs' import { Feed } from 'feed' import { createContentLoader } from 'vitepress' +import { isArticle, isNote } from './utils/content-type.mjs' import { comparePublicationDate, isPublished } from './utils/frontmatter.mjs' /** @typedef {import('vitepress').ContentData} ContentData */ @@ -9,18 +10,6 @@ import { comparePublicationDate, isPublished } from './utils/frontmatter.mjs' /** @todo: should come from .env */ const APP_URL = `https://blog.mehdi.cc` -/** - * @param {ContentData} content - * @param {string} type - */ -const isContentType = ({ url }, type) => url.startsWith(`/${type}s/`) - -/** @param {ContentData} content */ -const isArticle = content => isContentType(content, 'article') - -/** @param {ContentData} content */ -const isNote = content => isContentType(content, 'note') - /** @param {import('vitepress').SiteConfig} config */ export async function rss(config) { diff --git a/vitepress/.vitepress/utils/content-type.mjs b/vitepress/.vitepress/utils/content-type.mjs new file mode 100644 index 0000000..faf9211 --- /dev/null +++ b/vitepress/.vitepress/utils/content-type.mjs @@ -0,0 +1,23 @@ +/** @typedef {import('vitepress').ContentData} ContentData */ + +/** + * Check the type of content based on URL. + * + * @param {ContentData} content + * @param {string} type + */ +const isContentType = ({ url }, type) => url.startsWith(`/${type}s/`) + +/** + * The content is an article. + * + * @param {ContentData} content + */ +export const isArticle = content => isContentType(content, 'article') + +/** + * The content is a note. + * + * @param {ContentData} content + */ +export const isNote = content => isContentType(content, 'note') From 68302ac5b0c1ad1a6c5fe9ca1dbb86f99ac9c1bf Mon Sep 17 00:00:00 2001 From: Mehdi M Date: Sun, 19 Nov 2023 14:15:19 +0100 Subject: [PATCH 08/12] Extract authors --- vitepress/.vitepress/rss.mjs | 37 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/vitepress/.vitepress/rss.mjs b/vitepress/.vitepress/rss.mjs index 1ae0532..d132aeb 100644 --- a/vitepress/.vitepress/rss.mjs +++ b/vitepress/.vitepress/rss.mjs @@ -10,6 +10,13 @@ import { comparePublicationDate, isPublished } from './utils/frontmatter.mjs' /** @todo: should come from .env */ const APP_URL = `https://blog.mehdi.cc` +/** @type {import('feed/lib/feed.d.ts').Author[]} */ +const author = [{ + name: 'Mehdi Merah', + link: 'https://mehdi.cc', + email: 'hi@mehdi.cc', +}] + /** @param {import('vitepress').SiteConfig} config */ export async function rss(config) { @@ -48,11 +55,7 @@ export async function rss(config) { description: frontmatter.description || excerpt, content: html, date: frontmatter.publishedAt, - author: [{ - name: 'Mehdi Merah', - link: 'https://mehdi.cc', - email: 'hi@mehdi.cc', - }], + author, }) ) @@ -85,11 +88,7 @@ export async function rss(config) { description: frontmatter.description || excerpt, content: html, date: frontmatter.publishedAt, - author: [{ - name: 'Mehdi Merah', - link: 'https://mehdi.cc', - email: 'hi@mehdi.cc', - }], + author, }) ) @@ -122,11 +121,7 @@ export async function rss(config) { description: frontmatter.description || excerpt, content: html, date: frontmatter.publishedAt, - author: [{ - name: 'Mehdi Merah', - link: 'https://mehdi.cc', - email: 'hi@mehdi.cc', - }], + author, }) ) @@ -159,11 +154,7 @@ export async function rss(config) { description: frontmatter.description || excerpt, content: excerpt, date: frontmatter.publishedAt, - author: [{ - name: 'Mehdi Merah', - link: 'https://mehdi.cc', - email: 'hi@mehdi.cc', - }], + author, }) ) @@ -195,11 +186,7 @@ export async function rss(config) { description: frontmatter.description || excerpt, content: isNote({ url }) ? html : excerpt, date: frontmatter.publishedAt, - author: [{ - name: 'Mehdi Merah', - link: 'https://mehdi.cc', - email: 'hi@mehdi.cc', - }], + author, }) ) From b361b5d5b579d4e9881489ce26daa88acceebf70 Mon Sep 17 00:00:00 2001 From: Mehdi M Date: Sun, 19 Nov 2023 14:15:34 +0100 Subject: [PATCH 09/12] Rename feed with articles excerpts --- vitepress/.vitepress/rss.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vitepress/.vitepress/rss.mjs b/vitepress/.vitepress/rss.mjs index d132aeb..9e1dfc2 100644 --- a/vitepress/.vitepress/rss.mjs +++ b/vitepress/.vitepress/rss.mjs @@ -134,7 +134,7 @@ export async function rss(config) { const feedWithArticlesExcerptOnly = new Feed({ docs: 'https://www.rssboard.org/rss-specification', link: APP_URL, - title: 'Mehdi’s articles', + title: 'Mehdi’s articles (excerpts only)', description: 'Excerpt of my articles.', language: config.site.lang, // image: 'https://blog.mehdi.cc/file.png', From f757c3d84458b1c6c5020f3d100eca0efac5142c Mon Sep 17 00:00:00 2001 From: Mehdi M Date: Sun, 19 Nov 2023 17:13:35 +0100 Subject: [PATCH 10/12] Improve RSS code maintenance --- vitepress/.vitepress/rss.mjs | 203 ++++++++--------------------- vitepress/.vitepress/utils/rss.mjs | 74 +++++++++++ 2 files changed, 128 insertions(+), 149 deletions(-) create mode 100644 vitepress/.vitepress/utils/rss.mjs diff --git a/vitepress/.vitepress/rss.mjs b/vitepress/.vitepress/rss.mjs index 9e1dfc2..76a2871 100644 --- a/vitepress/.vitepress/rss.mjs +++ b/vitepress/.vitepress/rss.mjs @@ -1,194 +1,99 @@ -import path from 'path' -import { writeFileSync } from 'fs' import { Feed } from 'feed' import { createContentLoader } from 'vitepress' import { isArticle, isNote } from './utils/content-type.mjs' import { comparePublicationDate, isPublished } from './utils/frontmatter.mjs' - -/** @typedef {import('vitepress').ContentData} ContentData */ +import { baseFeedOptions, compareItemDate, feedItem, writeFeed } from './utils/rss.mjs' /** @todo: should come from .env */ const APP_URL = `https://blog.mehdi.cc` -/** @type {import('feed/lib/feed.d.ts').Author[]} */ -const author = [{ - name: 'Mehdi Merah', - link: 'https://mehdi.cc', - email: 'hi@mehdi.cc', -}] - /** @param {import('vitepress').SiteConfig} config */ export async function rss(config) { + const feedOptions = baseFeedOptions() - /** @type {ContentData[]} */ + // Load content and turn it into feed items. + + /** @type {import('vitepress').ContentData[]} */ const content = (await createContentLoader(['articles/*.md', 'notes/*.md'], { excerpt: true, render: true }).load()) .filter(isPublished) .toSorted(comparePublicationDate) - /** - * FULL CONTENT - */ + const notesItems = content.filter(isNote).map(feedItem) + const articlesItems = content.filter(isArticle).map(feedItem) + const articlesItemsExcerptOnly = content + .filter(isArticle) + .map(content => feedItem(content, { content: content.excerpt })) /** - * https://www.rssboard.org/rss-profile - * https://github.com/jpmonette/feed + * Generate all feeds and store them on disk. + * + * - spec: https://www.rssboard.org/rss-specification + * - spec best practices: https://www.rssboard.org/rss-profile + * - `feed` package: https://github.com/jpmonette/feed */ + + // Feed 1: full content + const feedWithEverything = new Feed({ - docs: 'https://www.rssboard.org/rss-specification', - link: APP_URL, title: 'Mehdi’s notes and articles', description: config.site.description, - language: config.site.lang, - // image: 'https://blog.mehdi.cc/file.png', - // favicon: `${APP_URL}/favicon.ico`, - copyright: 'Copyright © 2023-present, Mehdi Merah', feed: `${APP_URL}/feed.xml`, - ttl: 2880, // 1 day, - }); - - content - .forEach(({ url, excerpt, frontmatter, html }) => - feedWithEverything.addItem({ - title: frontmatter.title, - id: `${APP_URL}${url}`, - link: `${APP_URL}${url}`, - description: frontmatter.description || excerpt, - content: html, - date: frontmatter.publishedAt, - author, - }) - ) - - writeFileSync(path.join(config.outDir, 'feed.xml'), feedWithEverything.rss2()) + ...feedOptions, + }) - /** - * NOTES ONLY - */ + feedWithEverything.items = [...notesItems, ...articlesItems].toSorted(compareItemDate) - const feedWithNotesOnly = new Feed({ - docs: 'https://www.rssboard.org/rss-specification', - link: APP_URL, + writeFeed('feed', feedWithEverything) + + // Feed 2: notes + + const feedWithNotes = new Feed({ title: 'Mehdi’s notes', description: 'A chronological gathering of… notes.', - language: config.site.lang, - // image: 'https://blog.mehdi.cc/file.png', - // favicon: `${APP_URL}/favicon.ico`, - copyright: 'Copyright © 2023-present, Mehdi Merah', feed: `${APP_URL}/feed-notes-only.xml`, - ttl: 2880, // 1 day, - }); - - content - .filter(isNote) - .forEach(({ url, excerpt, frontmatter, html }) => - feedWithNotesOnly.addItem({ - title: frontmatter.title, - id: `${APP_URL}${url}`, - link: `${APP_URL}${url}`, - description: frontmatter.description || excerpt, - content: html, - date: frontmatter.publishedAt, - author, - }) - ) - - writeFileSync(path.join(config.outDir, 'feed-notes-only.xml'), feedWithNotesOnly.rss2()) + ...feedOptions, + }) - /** - * ARTICLES ONLY - */ + feedWithNotes.items = notesItems + + writeFeed('feed-notes-only', feedWithNotes) - const feedWithArticlesOnly = new Feed({ - docs: 'https://www.rssboard.org/rss-specification', - link: APP_URL, + // Feed 3: articles + + const feedWithArticles = new Feed({ title: 'Mehdi’s articles', description: 'A chronological gathering of… articles.', - language: config.site.lang, - // image: 'https://blog.mehdi.cc/file.png', - // favicon: `${APP_URL}/favicon.ico`, - copyright: 'Copyright © 2023-present, Mehdi Merah', feed: `${APP_URL}/feed-articles-only.xml`, - ttl: 2880, // 1 day, - }); + ...feedOptions, + }) - content - .filter(isArticle) - .forEach(({ url, excerpt, frontmatter, html }) => - feedWithArticlesOnly.addItem({ - title: frontmatter.title, - id: `${APP_URL}${url}`, - link: `${APP_URL}${url}`, - description: frontmatter.description || excerpt, - content: html, - date: frontmatter.publishedAt, - author, - }) - ) - - writeFileSync(path.join(config.outDir, 'feed-articles-only.xml'), feedWithArticlesOnly.rss2()) + feedWithArticles.items = articlesItems - /** - * ARTICLES EXCERPTS ONLY - */ + writeFeed('feed-articles-only', feedWithArticles) + + // Feed 4: articles excerpts - const feedWithArticlesExcerptOnly = new Feed({ - docs: 'https://www.rssboard.org/rss-specification', - link: APP_URL, + const feedWithArticlesExcerpts = new Feed({ title: 'Mehdi’s articles (excerpts only)', description: 'Excerpt of my articles.', - language: config.site.lang, - // image: 'https://blog.mehdi.cc/file.png', - // favicon: `${APP_URL}/favicon.ico`, - copyright: 'Copyright © 2023-present, Mehdi Merah', feed: `${APP_URL}/feed-articles-excerpts-only.xml`, - ttl: 2880, // 1 day, - }); + ...feedOptions, + }) - content - .filter(isArticle) - .forEach(({ url, excerpt, frontmatter, html }) => - feedWithArticlesExcerptOnly.addItem({ - title: frontmatter.title, - id: `${APP_URL}${url}`, - link: `${APP_URL}${url}`, - description: frontmatter.description || excerpt, - content: excerpt, - date: frontmatter.publishedAt, - author, - }) - ) - - writeFileSync(path.join(config.outDir, 'feed-articles-excerpts-only.xml'), feedWithArticlesExcerptOnly.rss2()) + feedWithArticlesExcerpts.items = articlesItemsExcerptOnly - /** - * ARTICLES EXCERPTS + NOTES - */ + writeFeed('feed-articles-excerpts-only', feedWithArticlesExcerpts) - const feedWithNotesAndArticlesExcerpts = new Feed({ - docs: 'https://www.rssboard.org/rss-specification', - link: APP_URL, + // Feed 5: articles excerpts and notes + + const feedWithArticlesExcerptsAndNotes = new Feed({ title: 'Mehdi’s light feed', description: 'Articles excerpts and notes.', - language: config.site.lang, - // image: 'https://blog.mehdi.cc/file.png', - // favicon: `${APP_URL}/favicon.ico`, - copyright: 'Copyright © 2023-present, Mehdi Merah', feed: `${APP_URL}/feed-articles-excerpts-and-notes.xml`, - ttl: 2880, // 1 day, - }); - - content - .forEach(({ url, excerpt, frontmatter, html }) => - feedWithNotesAndArticlesExcerpts.addItem({ - title: frontmatter.title, - id: `${APP_URL}${url}`, - link: `${APP_URL}${url}`, - description: frontmatter.description || excerpt, - content: isNote({ url }) ? html : excerpt, - date: frontmatter.publishedAt, - author, - }) - ) - - writeFileSync(path.join(config.outDir, 'feed-articles-excerpts-and-notes.xml'), feedWithNotesAndArticlesExcerpts.rss2()) + ...feedOptions, + }) + + feedWithArticlesExcerptsAndNotes.items = [...notesItems, ...articlesItemsExcerptOnly].toSorted(compareItemDate) + + writeFeed('feed-articles-excerpts-and-notes', feedWithArticlesExcerptsAndNotes) } diff --git a/vitepress/.vitepress/utils/rss.mjs b/vitepress/.vitepress/utils/rss.mjs new file mode 100644 index 0000000..d7d74fe --- /dev/null +++ b/vitepress/.vitepress/utils/rss.mjs @@ -0,0 +1,74 @@ +import path from 'path' +import { writeFileSync } from 'fs' +import { Feed } from 'feed' + +/** @typedef {import('feed').FeedOptions} FeedOptions */ +/** @typedef {import('feed').Item} Item */ +/** @typedef {import('vitepress').ContentData} ContentData */ +/** @typedef {import('vitepress').SiteConfig} SiteConfig */ + +/** @todo: should come from .env */ +const APP_URL = `https://blog.mehdi.cc` + +/** @type SiteConfig */ +let config = null + +/** + * Compare frontmatter publication date + * @param {Item} a + * @param {Item} b + */ +export const compareItemDate = (a, b) => new Date(b.date) - new Date(a.date) + +/** + * @param {SiteConfig} config + * @returns {FeedOptions} + */ +export const baseFeedOptions = siteConfig => { + if (!siteConfig) { + config = { ...siteConfig } + } + + return { + docs: 'https://www.rssboard.org/rss-specification', + link: APP_URL, + language: config.site.lang, + // image: 'https://blog.mehdi.cc/file.png', + // favicon: `${APP_URL}/favicon.ico`, + copyright: 'Copyright © 2023-present, Mehdi Merah', + ttl: 2880, // 1 day, + } +} + +/** + * @param {ContentData} content + * @param {Item?} overrides + * @returns {Item} + */ +export const feedItem = ({ url, excerpt, frontmatter, html }, { content } = null) => ({ + title: frontmatter.title, + id: `${APP_URL}${url}`, + link: `${APP_URL}${url}`, + description: frontmatter.description || excerpt, + content: content ?? html, + date: frontmatter.publishedAt, + author, +}) + +/** @type {import('feed').Author[]} */ +export const author = [{ + name: 'Mehdi Merah', + link: 'https://mehdi.cc', + email: 'hi@mehdi.cc', +}] + +/** + * Save a feed on the file system. + * + * @param {string} filename The name of the feed without file extension. + * @param {Feed} feed + */ +export const writeFeed = (filename, feed) => writeFileSync( + path.join(config.outDir, `${filename}.xml`), + feed.rss2(), +) From d37143629ea2d2b80d53eccc0a802b1dcfb18556 Mon Sep 17 00:00:00 2001 From: Mehdi M Date: Sun, 19 Nov 2023 17:18:11 +0100 Subject: [PATCH 11/12] Fix RSS config initialization --- vitepress/.vitepress/rss.mjs | 2 +- vitepress/.vitepress/utils/rss.mjs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vitepress/.vitepress/rss.mjs b/vitepress/.vitepress/rss.mjs index 76a2871..dc38a1b 100644 --- a/vitepress/.vitepress/rss.mjs +++ b/vitepress/.vitepress/rss.mjs @@ -9,7 +9,7 @@ const APP_URL = `https://blog.mehdi.cc` /** @param {import('vitepress').SiteConfig} config */ export async function rss(config) { - const feedOptions = baseFeedOptions() + const feedOptions = baseFeedOptions(config) // Load content and turn it into feed items. diff --git a/vitepress/.vitepress/utils/rss.mjs b/vitepress/.vitepress/utils/rss.mjs index d7d74fe..37371eb 100644 --- a/vitepress/.vitepress/utils/rss.mjs +++ b/vitepress/.vitepress/utils/rss.mjs @@ -25,7 +25,7 @@ export const compareItemDate = (a, b) => new Date(b.date) - new Date(a.date) * @returns {FeedOptions} */ export const baseFeedOptions = siteConfig => { - if (!siteConfig) { + if (!config) { config = { ...siteConfig } } From 40cd6d089b0581b0000da81c367175e304a77433 Mon Sep 17 00:00:00 2001 From: Mehdi M Date: Sun, 19 Nov 2023 17:21:17 +0100 Subject: [PATCH 12/12] Rename function comparing RSS items dates --- vitepress/.vitepress/rss.mjs | 6 +++--- vitepress/.vitepress/utils/rss.mjs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/vitepress/.vitepress/rss.mjs b/vitepress/.vitepress/rss.mjs index dc38a1b..c121435 100644 --- a/vitepress/.vitepress/rss.mjs +++ b/vitepress/.vitepress/rss.mjs @@ -2,7 +2,7 @@ import { Feed } from 'feed' import { createContentLoader } from 'vitepress' import { isArticle, isNote } from './utils/content-type.mjs' import { comparePublicationDate, isPublished } from './utils/frontmatter.mjs' -import { baseFeedOptions, compareItemDate, feedItem, writeFeed } from './utils/rss.mjs' +import { baseFeedOptions, compareItemsDates, feedItem, writeFeed } from './utils/rss.mjs' /** @todo: should come from .env */ const APP_URL = `https://blog.mehdi.cc` @@ -41,7 +41,7 @@ export async function rss(config) { ...feedOptions, }) - feedWithEverything.items = [...notesItems, ...articlesItems].toSorted(compareItemDate) + feedWithEverything.items = [...notesItems, ...articlesItems].toSorted(compareItemsDates) writeFeed('feed', feedWithEverything) @@ -93,7 +93,7 @@ export async function rss(config) { ...feedOptions, }) - feedWithArticlesExcerptsAndNotes.items = [...notesItems, ...articlesItemsExcerptOnly].toSorted(compareItemDate) + feedWithArticlesExcerptsAndNotes.items = [...notesItems, ...articlesItemsExcerptOnly].toSorted(compareItemsDates) writeFeed('feed-articles-excerpts-and-notes', feedWithArticlesExcerptsAndNotes) } diff --git a/vitepress/.vitepress/utils/rss.mjs b/vitepress/.vitepress/utils/rss.mjs index 37371eb..d33d579 100644 --- a/vitepress/.vitepress/utils/rss.mjs +++ b/vitepress/.vitepress/utils/rss.mjs @@ -18,7 +18,7 @@ let config = null * @param {Item} a * @param {Item} b */ -export const compareItemDate = (a, b) => new Date(b.date) - new Date(a.date) +export const compareItemsDates = (a, b) => new Date(b.date) - new Date(a.date) /** * @param {SiteConfig} config