Skip to content

Commit

Permalink
Add How to generate an RSS feed post (#24)
Browse files Browse the repository at this point in the history
* migrate rss lib to TS

* remove commented code

* fix createPost script

* add www to site url

* add rss post
  • Loading branch information
pducolin authored Feb 28, 2024
1 parent 7356030 commit 33b73f7
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 20 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"type": "module",
"scripts": {
"new": "node scripts/createPost.js",
"new": "yarn tsx src/scripts/createPost.ts",
"dev": "next dev",
"build": "next build",
"start": "yarn serve out",
Expand Down
68 changes: 68 additions & 0 deletions posts/How-to-add-an-RSS-feed-to-your-Nextjs-blog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
title: "How to add an RSS feed to your Next.js blog"
author: "poladuco"
date: "2024-02-28"
heroImage:
path:
big: /assets/images/update.webp
small: /assets/images/update_small.webp
alt: Update text on paper page in a typewriter, photo by Markus Winkler on Unsplash
---

After my [last post](https://www.poladuco.com/post/my-path-to-staff-engineer) a colleague reached out with a usefull feedback: what about adding an RSS feed, so that people could keep track of new content?

## What is an RSS feed?

An RSS feed is an XML file that contains the list of contents of a website, such as articles, news and episodes. It follows the [RSS specification](https://www.rssboard.org/rss-specification) and RSS clients regularly monitor feeds to keep track of updates.

The `rss` root node contains one `channel` node. The `channel` node contains the blog overall information and can contain one or more `item` nodes, each one defining a blog post:

```xml
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<atom:link href="<url to the rss feed>" rel="self" type="application/rss+xml"/>
<title> blog title </title>
<link> blog url </link>
<description> blog description </description>
<language> en </language>
<lastBuildDate> RFC 822 formatted date and time of last update </lastBuildDate>
<item>
<title> Post title </title>
<link> Post link </link>
<author> author's email </author>
<pubDate> RFC 822 formatted date and time of publication </pubDate>
<guid> unique ID of the blog post </guid>
</item>
</channel>
</rss>
```

W3C maintains a [free RSS validator](https://validator.w3.org/feed/) that I used to ensure my feed was well formatted.

## RSS feed and Next.js

Next.js supports server side [static export](https://nextjs.org/docs/pages/building-your-application/deploying/static-exports): I generate my blog HTML and CSS content at build time, when I push my updates to Github. When a browser opens my blog it loads static HTML pages generated the last time I pushed my code.

Next.js static export generates only HTML, but it can [serve any static content](https://nextjs.org/docs/pages/building-your-application/optimizing/static-assets), under the `public` folder.

I already had code to load my markdown posts, I wanted to use it at build time to generate the feed and add it to the `public` folder.

Next.js loads the `public` folder content at build time, but content must be ready when `next build` starts. I did not want to generate the content dynamically as it the feed is as static as my posts. I did not want to commit a generated feed to Github neither, so I used my CI to generate it at build time, before it calls Next.js build command.

## Generate the feed

I added [a TS library](https://github.com/pducolin/blog/blob/main/src/lib/rss.ts) to generate an RSS feed in Node, using the code that I use to generate my posts in Next.js. I prefered writing my code to play with RSS, but there are public libraries like [feed](https://github.com/jpmonette/feed).

I defined `yarn rss` in `scripts` in my `package.json` to have a shortcut to generate the feed.

```json
"rss": "yarn tsx src/scripts/createRSS.ts"
```
Last step was calling it before I call the `next build` command in my CI. I updated the `command` in the `build` section in `netflify.toml` using the `&&` [bash operator](https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Lists) to first call `yarn rss` and then `yarn run build`, if the rss generation succeeds. This way Netlify generates the rss feed and right after Next.js finds it in `public`:

```toml
[build]
command = "yarn rss && yarn run build"
```

That's it! Now you can use [the generated RSS feed](https://www.poladuco.com/rss.xml) to track my content for updates.
Binary file added public/assets/images/update.webp
Binary file not shown.
Binary file added public/assets/images/update_small.webp
Binary file not shown.
17 changes: 0 additions & 17 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,6 @@ import React from "react"
import {config} from "config/sitemap"
import { getSortedPostsData } from "lib/posts"

// export const metadata: Metadata = {
// title: '...',
// }

{/* Open Graph */}
{/* <meta property="og:url" content={currentURL} key="ogurl" />
<meta property="og:image" content={previewImage} key="ogimage" />
<meta property="og:site_name" content="poladuco.com" key="ogsitename" />
<meta property="og:title" content={pageTitle} key="ogtitle" />
<meta property="og:description" content={description} key="ogdesc" /> */}
// {/* <meta property="og:type" content={isPost ? "article" : "website"} key="ogtype" /> */}


// {/* <title>{pageTitle}</title> */}
// </Head> */}


const Index = () => {
const posts = getSortedPostsData()

Expand Down
2 changes: 1 addition & 1 deletion src/config/sitemap.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ export const config = {
description: "Sharing my enthusiasm about tech",
siteName: "poladuco.com",
previewImage: "/assets/images/default.webp",
siteURL: "https://poladuco.com",
siteURL: "https://www.poladuco.com",
twitterHandle: "@PolaDuco"
}
File renamed without changes.
7 changes: 6 additions & 1 deletion src/scripts/createPost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ import "colors"

import { createInterface } from "readline"
import { writeFileSync } from "fs"
import { fileURLToPath } from 'url';
import { dirname } from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const log = console.log

Expand Down Expand Up @@ -59,7 +64,7 @@ Apple pie jelly candy. Tiramisu fruitcake jelly beans lollipop. Gummies bonbon p
// * i "ignore upper/lower case differences"
// * g "global, match every instance"
.replace(/[^a-z0-9-]/gi, "")
writeFileSync(__dirname + `/../posts/${filename}.md`, header)
writeFileSync(__dirname + `/../../posts/${filename}.md`, header)
console.log(`Done, go to ${filename} and start writing`.green)
}

Expand Down

0 comments on commit 33b73f7

Please sign in to comment.