on master help sign in
meta: generate rss feed of all blog posts, events, updates
commit574c4ef459ac42788859019a3b679a0232f7920b authorMatilde Park <matilde@tlon.io> dateTue 27 Jul 2021, 19:10 (5 years ago) parent616ac28
5 files changed+126−3
.gitignore+2 components/Meta.js+6 lib/rss.js+97 package-lock.json+16 package.json+5−3
.gitignore+2
@@ -5,6 +5,8 @@
55/.pnp
66.pnp.js
77
8+/public
9+
810# testing
911/coverage
1012
components/Meta.js+6
@@ -20,6 +20,12 @@ export default function Meta(post) {
2020 <meta name="description" content={description} />
2121 <meta name="author" content={author} key="author" />
2222 <meta name="twitter:image" content={image} key="image" />
23+ <link
24+ rel="alternative"
25+ type="application/rss+xml"
26+ title="RSS"
27+ href="/rss.xml"
28+ />
2329 </>
2430 );
2531}
lib/rss.jsnew file+97
@@ -0,0 +1,97 @@
1+const fs = require("fs");
2+const path = require("path");
3+const matter = require("gray-matter");
4+const toml = require("@iarna/toml");
5+const Feed = require("feed").Feed;
6+
7+const options = {
8+ engines: {
9+ toml: toml.parse.bind(toml),
10+ },
11+ language: "toml",
12+ delimiters: "+++",
13+};
14+
15+const generateRSSFeed = () => {
16+ let posts = [];
17+
18+ const getAllChildren = (dir) => {
19+ const children = fs.readdirSync(dir, { withFileTypes: true });
20+ return children
21+ .filter((f) => f.isFile() && f.name !== "_index.md")
22+ .map((post) => {
23+ const { data: pageData, content: pageContent } = matter(
24+ fs.readFileSync(path.join(dir, post.name)),
25+ options
26+ );
27+ return {
28+ title: pageData.title,
29+ descripton: pageData.description || "",
30+ author: pageData.extra.author || "",
31+ date: pageData.date,
32+ link: path.join(
33+ "https://urbit.org/",
34+ dir.substr(dir.indexOf("content") + 7),
35+ "/",
36+ post.name.replace(/.md$/, "")
37+ ),
38+ content: pageContent,
39+ };
40+ });
41+ };
42+ posts.push(
43+ ...getAllChildren(path.join(process.cwd(), "content/blog")),
44+ ...getAllChildren(path.join(process.cwd(), "content/updates")),
45+ ...getAllChildren(path.join(process.cwd(), "content/events"))
46+ );
47+ posts = posts.sort((a, b) => (a.date > b.date ? -1 : 1));
48+
49+ const baseUrl = "https://urbit.org";
50+ const author = {
51+ name: "Urbit.org",
52+ email: "support@urbit.org",
53+ link: "https://urbit.org",
54+ };
55+
56+ // Construct a new Feed object
57+ const feed = new Feed({
58+ title: "Urbit",
59+ description: "Urbit is a personal server built from scratch",
60+ id: baseUrl,
61+ link: baseUrl,
62+ language: "en",
63+ feedLinks: {
64+ rss2: `${baseUrl}/rss.xml`,
65+ },
66+ author,
67+ });
68+
69+ // Add each article to the feed
70+ posts.forEach((post) => {
71+ const { title, description, author, date, link, content } = post;
72+ feed.addItem({
73+ title,
74+ id: link,
75+ link: link,
76+ description,
77+ content,
78+ author: [
79+ {
80+ name: author,
81+ email: "",
82+ link: "",
83+ },
84+ ],
85+ date: new Date(date),
86+ });
87+ });
88+ try {
89+ fs.readdirSync("public");
90+ } catch (err) {
91+ fs.mkdirSync("public");
92+ }
93+
94+ fs.writeFileSync("public/rss.xml", feed.rss2());
95+};
96+
97+generateRSSFeed();
package-lock.json+16
@@ -2897,6 +2897,14 @@
28972897 "reusify": "^1.0.4"
28982898 }
28992899 },
2900+ "feed": {
2901+ "version": "4.2.2",
2902+ "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz",
2903+ "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==",
2904+ "requires": {
2905+ "xml-js": "^1.6.11"
2906+ }
2907+ },
29002908 "file-type": {
29012909 "version": "10.11.0",
29022910 "resolved": "https://registry.npmjs.org/file-type/-/file-type-10.11.0.tgz",
@@ -6828,6 +6836,14 @@
68286836 "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.2.tgz",
68296837 "integrity": "sha512-lkF7AWRicoB9mAgjeKbGqVUekLnSNO4VjKVnuPHpQeOxZOErX6BPXwJk70nFslRCEEA8EVW7ZjKwXaP9N+1sKQ=="
68306838 },
6839+ "xml-js": {
6840+ "version": "1.6.11",
6841+ "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz",
6842+ "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==",
6843+ "requires": {
6844+ "sax": "^1.2.4"
6845+ }
6846+ },
68316847 "xml-name-validator": {
68326848 "version": "3.0.0",
68336849 "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
package.json+5−3
@@ -3,12 +3,13 @@
33 "version": "0.1.0",
44 "private": true,
55 "scripts": {
6− "dev": "npm run cache-posts && next dev",
7− "build": "npm run cache-posts && next build",
8− "export": "npm run cache-posts && next build && next export",
6+ "dev": "npm run cache-posts && npm run rss && next dev",
7+ "build": "npm run cache-posts && npm run rss && next build",
8+ "export": "npm run cache-posts && npm run rss && next build && next export",
99 "start": "next start",
1010 "prepare": "husky install",
1111 "cache-posts": "node lib/cache.js",
12+ "rss": "node lib/rss.js",
1213 "postinstall": "patch-package"
1314 },
1415 "dependencies": {
@@ -17,6 +18,7 @@
1718 "autoprefixer": "^10.2.6",
1819 "classnames": "^2.3.1",
1920 "critters": "0.0.10",
21+ "feed": "^4.2.2",
2022 "fuzzy-search": "^3.2.1",
2123 "gray-matter": "^4.0.3",
2224 "html-entities": "^2.3.2",