Skip to content

Commit

Permalink
Add RSS generation script and hook it into build [#932]
Browse files Browse the repository at this point in the history
* Add function to `blogPosts.js` to read blog post and generate feeds
  with the 10 most recent posts into the `public/blog` directory
* Hoist `__dirname` constant up to the top-level of `blogPosts.js` to
  facilitate re-use
* Add new top-level script that calls the new `generateBlogFeeds()` function
* Add package.json:scripts target to run this script
* Hook that package.json:scripts target into build.sh
* Add `<link>` element for each feed file to template `<head>`
* Ignore the new build-time generated files
  • Loading branch information
genehack committed Aug 23, 2024
1 parent 9347c1e commit 70209e0
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 2 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,9 @@ static-site/.next

# TypeScript
static-site/tsconfig.tsbuildinfo

# Blog feeds
static-site/public/blog/atom.xml
static-site/public/blog/feed.json
static-site/public/blog/rss2.xml

1 change: 1 addition & 0 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ main() {

build-static() {
echo "Building the static Next.JS app (pages defined in static-site/pages, assets written to static-site/.next)"
npm run build:feeds
./node_modules/.bin/next build static-site
}

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
},
"scripts": {
"build": "./build.sh",
"build:feeds": "node scripts/generate-blog-feeds.js",
"lint": "npm run lint:server",
"lint:server": "DEBUG=eslint:cli-engine npx eslint --ext .js,.jsx .",
"lint:static-site": "cd static-site && DEBUG=eslint:cli-engine npx eslint --ext .js,.jsx,.ts,.tsx .",
Expand Down
3 changes: 3 additions & 0 deletions scripts/generate-blog-feeds.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { generateBlogFeeds } from "../static-site/src/util/blogPosts.js";

await generateBlogFeeds();
5 changes: 4 additions & 1 deletion static-site/src/components/layout.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from "react";
import Helmet from "react-helmet";
import styled, {ThemeProvider} from "styled-components";
import { siteTitle, siteDescription } from "../../data/SiteConfig";
import { siteTitle, siteDescription, siteUrl } from "../../data/SiteConfig";
import {theme} from '../layouts/theme';

/**
Expand All @@ -23,6 +23,9 @@ export default class MainLayout extends React.Component {
<title>{`${siteTitle}`}</title>
<meta name="description" content={siteDescription} />
<link rel="me" href="https://mstdn.science/@nextstrain" />
<link href={`${siteUrl}/blog/atom.xml`} rel="alternate" title="Atom feed for nextstrain.org/blog" type="application/atom+xml" />
<link href={`${siteUrl}/blog/feed.json`} rel="alternate" title="JSON feed for nextstrain.org/blog" type="application/json" />
<link href={`${siteUrl}/blog/rss2.xml`} rel="alternate" title="RSS2 feed for nextstrain.org/blog" type="application/rss+xml" />
</Helmet>
<ThemeProvider theme={theme}>
<GlobalStyles>
Expand Down
76 changes: 75 additions & 1 deletion static-site/src/util/blogPosts.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,21 @@ import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import matter from 'gray-matter';
import { Feed } from 'feed';
import { parseMarkdown } from "./parseMarkdown.js";
import lodash from 'lodash';

const { startCase } = lodash;

const NUMBER_OF_POSTS_IN_FEED = 10;
const __dirname = path.dirname(fileURLToPath(import.meta.url));

/**
* Scans the ./static-site/content/blog directory for .md files
* and returns a chronologically sorted array of posts, each with
* some basic metadata and the raw (unsanitized) markdown contents.
*/
export function getBlogPosts() {
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const postsDirectory = path.join(__dirname, "..", "..", "content", "blog")
const markdownFiles = fs.readdirSync(postsDirectory)
.filter((fileName) => fileName.endsWith(".md"));
Expand All @@ -38,6 +42,76 @@ export function getBlogPosts() {
return blogPosts;
}

/**
* Writes RSS2, Atom, and JSON feeds into the `public/blog` directory.
*/
export async function generateBlogFeeds() {
const feedDir = `${__dirname}/../../public/blog`;
const siteURL = "https://nextstrain.org/blog";

const feed = new Feed({
title: "Nextstrain.org Blog",
description: "FIXME",
id: siteURL,
link: siteURL,
image: "https://nextstrain.org/_next/static/media/nextstrain-logo-small.dcf6bdd2.png",
favicon: "https://nextstrain.org/favicon.ico",
copyright: "Copyright Trevor Bedford and Richard Neher.",
updated: new Date(),
feedLinks: {
atom: `${siteURL}/atom.xml`,
json: `${siteURL}/feed.json`,
rss2: `${siteURL}/rss2.xml`,
},
author: {
name: "The Nextstrain Team",
email: "hello@nextstrain.org",
link: "https://nextstrain.org",
},
});

const posts = getBlogPosts().slice(0, NUMBER_OF_POSTS_IN_FEED);

for (const post of posts) {
if (post) { // getBlogPosts() _might_ return `false` list members
try {
const content = parseMarkdown(post.mdstring);
const url = `${siteURL}/${post.blogUrlName}`;

feed.addItem({
author: [ { name: post.author } ],
content: content,
date: new Date(post.date),
id: url,
link: url,
title: post.title,
});
} catch (error) {
console.error(`Skipping post entitled "${post.title}" due to Markdown parsing error:\n${error}`);
}
}
}

const feeds = [
{
file: `${feedDir}/atom.xml`,
data: feed.atom1,
},
{
file: `${feedDir}/feed.json`,
data: feed.json1,
},
{
file: `${feedDir}/rss2.xml`,
data: feed.rss2,
},
];

for (const feed of feeds) {
fs.writeFileSync(feed.file, feed.data());
}
}

/**
* strip out the YYYY-MM-DD- leading string from blog-post filenames and return
* the rest of the filename converted to start case (first letter of each word
Expand Down

0 comments on commit 70209e0

Please sign in to comment.