tangled
alpha
login
or
join now
danabra.mov
/
overreacted
51
fork
atom
my blog https://overreacted.io
51
fork
atom
overview
issues
pulls
2
pipelines
fix local build
danabra.mov
10 months ago
308dafec
a988f7e3
+74
-74
5 changed files
expand all
collapse all
unified
split
app
atom.xml
route.js
feed.js
page.js
posts.js
rss.xml
route.js
+2
-4
app/atom.xml/route.js
···
1
1
-
import { getPosts, metadata } from "../page";
2
2
-
import { generateFeed } from "../feed";
1
1
+
import { generateFeed } from "../posts";
3
2
4
3
export const dynamic = "force-static";
5
4
6
5
export async function GET() {
7
7
-
const posts = await getPosts();
8
8
-
const feed = generateFeed(posts, metadata);
6
6
+
const feed = await generateFeed();
9
7
return new Response(feed.atom1());
10
8
}
-35
app/feed.js
···
1
1
-
import { Feed } from "feed";
2
2
-
3
3
-
export function generateFeed(posts, metadata) {
4
4
-
const site_url = "https://overreacted.io/";
5
5
-
6
6
-
const feedOptions = {
7
7
-
author: {
8
8
-
name: "Dan Abramov",
9
9
-
email: "dan.abramov@gmail.com",
10
10
-
link: site_url,
11
11
-
},
12
12
-
description: metadata.description,
13
13
-
favicon: `${site_url}/icon.png`,
14
14
-
feedLinks: { atom: `${site_url}atom.xml`, rss: `${site_url}rss.xml` },
15
15
-
generator: "Feed for Node.js",
16
16
-
id: site_url,
17
17
-
image: "https://github.com/gaearon.png",
18
18
-
link: site_url,
19
19
-
title: metadata.title,
20
20
-
};
21
21
-
22
22
-
const feed = new Feed(feedOptions);
23
23
-
24
24
-
for (const post of posts) {
25
25
-
feed.addItem({
26
26
-
date: new Date(post.date),
27
27
-
description: post.spoiler,
28
28
-
id: `${site_url}${post.slug}/`,
29
29
-
link: `${site_url}${post.slug}/`,
30
30
-
title: post.title,
31
31
-
});
32
32
-
}
33
33
-
34
34
-
return feed;
35
35
-
}
+2
-31
app/page.js
···
1
1
-
import { readdir, readFile } from "fs/promises";
2
2
-
import matter from "gray-matter";
3
1
import Link from "./Link";
4
2
import Color from "colorjs.io";
3
3
+
import { metadata, getPosts } from "./posts";
5
4
import { sans } from "./fonts";
6
5
7
7
-
export const metadata = {
8
8
-
title: "overreacted — A blog by Dan Abramov",
9
9
-
description: "A personal blog by Dan Abramov",
10
10
-
alternates: {
11
11
-
types: {
12
12
-
"application/atom+xml": "https://overreacted.io/atom.xml",
13
13
-
"application/rss+xml": "https://overreacted.io/rss.xml",
14
14
-
},
15
15
-
},
16
16
-
};
17
17
-
18
18
-
export async function getPosts() {
19
19
-
const entries = await readdir("./public/", { withFileTypes: true });
20
20
-
const dirs = entries
21
21
-
.filter((entry) => entry.isDirectory())
22
22
-
.map((entry) => entry.name);
23
23
-
const fileContents = await Promise.all(
24
24
-
dirs.map((dir) => readFile("./public/" + dir + "/index.md", "utf8")),
25
25
-
);
26
26
-
const posts = dirs.map((slug, i) => {
27
27
-
const fileContent = fileContents[i];
28
28
-
const { data } = matter(fileContent);
29
29
-
return { slug, ...data };
30
30
-
});
31
31
-
posts.sort((a, b) => {
32
32
-
return Date.parse(a.date) < Date.parse(b.date) ? 1 : -1;
33
33
-
});
34
34
-
return posts;
35
35
-
}
6
6
+
export { metadata };
36
7
37
8
export default async function Home() {
38
9
const posts = await getPosts();
+68
app/posts.js
···
1
1
+
import { readdir, readFile } from "fs/promises";
2
2
+
import matter from "gray-matter";
3
3
+
import { Feed } from "feed";
4
4
+
5
5
+
export const metadata = {
6
6
+
title: "overreacted — A blog by Dan Abramov",
7
7
+
description: "A personal blog by Dan Abramov",
8
8
+
alternates: {
9
9
+
types: {
10
10
+
"application/atom+xml": "https://overreacted.io/atom.xml",
11
11
+
"application/rss+xml": "https://overreacted.io/rss.xml",
12
12
+
},
13
13
+
},
14
14
+
};
15
15
+
16
16
+
export async function getPosts() {
17
17
+
const entries = await readdir("./public/", { withFileTypes: true });
18
18
+
const dirs = entries
19
19
+
.filter((entry) => entry.isDirectory())
20
20
+
.map((entry) => entry.name);
21
21
+
const fileContents = await Promise.all(
22
22
+
dirs.map((dir) => readFile("./public/" + dir + "/index.md", "utf8")),
23
23
+
);
24
24
+
const posts = dirs.map((slug, i) => {
25
25
+
const fileContent = fileContents[i];
26
26
+
const { data } = matter(fileContent);
27
27
+
return { slug, ...data };
28
28
+
});
29
29
+
posts.sort((a, b) => {
30
30
+
return Date.parse(a.date) < Date.parse(b.date) ? 1 : -1;
31
31
+
});
32
32
+
return posts;
33
33
+
}
34
34
+
35
35
+
export async function generateFeed() {
36
36
+
const posts = await getPosts();
37
37
+
const site_url = "https://overreacted.io/";
38
38
+
39
39
+
const feedOptions = {
40
40
+
author: {
41
41
+
name: "Dan Abramov",
42
42
+
email: "dan.abramov@gmail.com",
43
43
+
link: site_url,
44
44
+
},
45
45
+
description: metadata.description,
46
46
+
favicon: `${site_url}/icon.png`,
47
47
+
feedLinks: { atom: `${site_url}atom.xml`, rss: `${site_url}rss.xml` },
48
48
+
generator: "Feed for Node.js",
49
49
+
id: site_url,
50
50
+
image: "https://github.com/gaearon.png",
51
51
+
link: site_url,
52
52
+
title: metadata.title,
53
53
+
};
54
54
+
55
55
+
const feed = new Feed(feedOptions);
56
56
+
57
57
+
for (const post of posts) {
58
58
+
feed.addItem({
59
59
+
date: new Date(post.date),
60
60
+
description: post.spoiler,
61
61
+
id: `${site_url}${post.slug}/`,
62
62
+
link: `${site_url}${post.slug}/`,
63
63
+
title: post.title,
64
64
+
});
65
65
+
}
66
66
+
67
67
+
return feed;
68
68
+
}
+2
-4
app/rss.xml/route.js
···
1
1
-
import { getPosts, metadata } from "../page";
2
2
-
import { generateFeed } from "../feed";
1
1
+
import { generateFeed } from "../posts";
3
2
4
3
export const dynamic = "force-static";
5
4
6
5
export async function GET() {
7
7
-
const posts = await getPosts();
8
8
-
const feed = generateFeed(posts, metadata);
6
6
+
const feed = await generateFeed();
9
7
return new Response(feed.rss2());
10
8
}