Skip to content

Commit 3ec6393

Browse files
committed
fix(blog): parse blog tree to use absolute image paths
1 parent 7886ec1 commit 3ec6393

3 files changed

Lines changed: 145 additions & 51 deletions

File tree

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@
3434
"react-dom": "19.2.3",
3535
"rehype-slug": "^6.0.0",
3636
"rehype-unwrap-images": "^1.0.0",
37+
"remark": "^15.0.1",
3738
"remark-gfm": "^4.0.1",
39+
"remark-html": "^16.0.1",
3840
"sonner": "^2.0.6",
3941
"tailwind-merge": "^3.3.1",
4042
"vaul": "^1.1.2",
@@ -57,6 +59,7 @@
5759
"tailwindcss": "^4",
5860
"tw-animate-css": "^1.3.4",
5961
"typescript": "^5",
62+
"unist-util-visit": "^5.1.0",
6063
"wrangler": "^4.58.0"
6164
},
6265
"pnpm": {

pnpm-lock.yaml

Lines changed: 71 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app/blog/rss/route.ts

Lines changed: 71 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,82 @@
11
import { Feed } from "feed";
2+
import { remark } from "remark";
3+
import html from "remark-html";
4+
import remarkGfm from "remark-gfm";
5+
import { visit } from "unist-util-visit";
26
import { posts } from "@/utils/posts";
37

48
export const dynamic = "force-static";
59

6-
export async function GET() {
7-
const allPosts = posts.getPosts();
8-
const latestPost = allPosts[0];
9-
const siteUrl = process.env.NEXT_PUBLIC_BASE_URL || "https://jacobmoy.com";
10-
const author = {
11-
name: "Jacob Moy",
12-
email: "me@jacobmoy.com",
13-
link: siteUrl,
10+
function remarkAbsoluteImages(options: { siteUrl: string }) {
11+
return (tree: any) => {
12+
visit(tree, "image", (node: any) => {
13+
if (node.url.startsWith("/")) {
14+
node.url = `${options.siteUrl}${node.url}`;
15+
}
16+
});
1417
};
18+
}
1519

16-
const feed = new Feed({
17-
title: "Jacob Moy | Blog",
18-
description: "Jacob Moy's personal blog about software development, technology, and life.",
19-
id: siteUrl,
20-
link: siteUrl,
21-
language: "en",
22-
image: `${siteUrl}/favicon.ico`,
23-
favicon: `${siteUrl}/favicon.ico`,
24-
copyright: `All rights reserved ${new Date().getFullYear()}, Jacob Moy`,
25-
updated: latestPost ? new Date(latestPost.date) : new Date(),
26-
generator: "Feed for Node.js",
27-
feedLinks: {
28-
rss2: `${siteUrl}/blog/rss`,
29-
},
30-
author: author,
31-
});
20+
export async function GET() {
21+
try {
22+
const allPosts = posts.getPosts();
23+
const latestPost = allPosts[0];
24+
const siteUrl = process.env.NEXT_PUBLIC_BASE_URL || "https://jacobmoy.com";
25+
const author = {
26+
name: "Jacob Moy",
27+
email: "me@jacobmoy.com",
28+
link: siteUrl,
29+
};
3230

33-
allPosts.forEach((post) => {
34-
const url = `${siteUrl}/blog/posts/${post.slug}`;
35-
feed.addItem({
36-
title: post.title,
37-
id: url,
38-
link: url,
39-
description: post.description,
40-
content: post.content,
41-
author: [author],
42-
contributor: [author],
43-
date: new Date(post.date),
44-
image: post.image ? `${siteUrl}${post.image}` : undefined,
31+
const feed = new Feed({
32+
title: "Jacob Moy | Blog",
33+
description: "Jacob Moy's personal blog about software development, technology, and life.",
34+
id: siteUrl,
35+
link: siteUrl,
36+
language: "en",
37+
image: `${siteUrl}/favicon.ico`,
38+
favicon: `${siteUrl}/favicon.ico`,
39+
copyright: `All rights reserved ${new Date().getFullYear()}, Jacob Moy`,
40+
updated: latestPost ? new Date(latestPost.date) : new Date(),
41+
generator: "Feed for Node.js",
42+
feedLinks: {
43+
rss2: `${siteUrl}/blog/rss`,
44+
},
45+
author: author,
4546
});
46-
});
4747

48-
return new Response(feed.rss2(), {
49-
headers: {
50-
"Content-Type": "application/xml",
51-
"Cache-Control": "s-maxage=3600, stale-while-revalidate",
52-
},
53-
});
48+
for (const post of allPosts) {
49+
const url = `${siteUrl}/blog/posts/${post.slug}`;
50+
const processedContent = await remark()
51+
.use(remarkGfm)
52+
.use(remarkAbsoluteImages, { siteUrl })
53+
.use(html)
54+
.process(post.content);
55+
const contentHtml = processedContent.toString();
56+
57+
feed.addItem({
58+
title: post.title,
59+
id: url,
60+
link: url,
61+
description: post.description,
62+
content: contentHtml,
63+
author: [author],
64+
contributor: [author],
65+
date: new Date(post.date),
66+
image: post.image ? `${siteUrl}${post.image}` : undefined,
67+
});
68+
}
69+
70+
return new Response(feed.rss2(), {
71+
headers: {
72+
"Content-Type": "application/xml",
73+
"Cache-Control": "s-maxage=3600, stale-while-revalidate",
74+
},
75+
});
76+
} catch (e: any) {
77+
console.error(e);
78+
return new Response(`Error generating RSS feed: ${e.message}\n${e.stack}`, {
79+
status: 500,
80+
});
81+
}
5482
}

0 commit comments

Comments
 (0)