📡

Github Pages 上に JAMstack 構成の簡素な自分用RSSリーダーを作ってみた

2024/11/22に公開

JavaScript での RSS 収集方法や、Github Pagesのデプロイ方法など、車輪の再発明について備忘録がてら書きまとめた記事です。

github:
https://github.com/para7/tech-rss-portal

デプロイしたページ:
https://para7.github.io/tech-rss-portal/

何もかもを削っているので表示は神速です。代わりにTODOが山積み。

経緯

  • 定期的に見る技術ブログをまとめたい
  • RSS を使えばまとめられそう
  • RSS リーダーを使えば良いが、xmlを収集する程度なら自前実装できるのではないか?
  • 諸々の練習として良いテーマなのでは?

→ 自作しよう!

技術選定

要件、やるべきことを整理してみます。

  • ローカルアプリよりデプロイした方が使いやすいが、サイトのメンテナンスをしたくない。運用コストもかけたくない
  • データ取得=相手方へのサーバー負荷は最低限にしたい。DBにキャッシュするか、SSGが理想
  • SSGなら、定期的にビルドがいる
  • 画面の動的要素は最低限でよく、読み込み速度優先でよい

メンテは楽な方がいいですよね。特にデータベースは持ちたくありません。
可能なら SSR ではなく、 SSG (JAMstack) でどうにかしたいところです。

JAMstack ですと cron スケジューラーの調達が問題になります。
思いついてGithub Actions の規約を調べてみたところ、低負荷アクションであれば個人的用途で使っても見逃してもらえるようでした。

https://docs.github.com/ja/site-policy/github-terms/github-terms-for-additional-products-and-features#actions

当社のサーバーに負担をかけるアクティビティで、その負担がユーザーに提供される利益に見合わない場合 (たとえば、Actions をコンテンツ配信ネットワークまたはサーバーレス アプリケーションの一部として使用しないでください。ただし、利益の小さい Action でも負荷が小さければ問題ありません)、または、

RSSリーダーに1日中張り付いて確認することはないので、Github Actions を使って1日1回ビルドすることにしました。発火タイミングも0分などキリの良い時間を避けて、へんてこな時間を設定します。これで怒られることはないはず。

サーバーランタイム不要かつ、Github Actions を前提にするなら、そのまま Github Pages に置くのが認証周りの手間もなくてよさそうです。デプロイ先も決定です。

さて最後に、サイト自体の実装としては、私の慣れている React か Svelte が選択肢です。
リッチな機能はいらないので、JSサイズを減らす目的で React ではなく Svelte を選びました。


というわけで、要件への回答としては

  • サイトのメンテナンスをしたくない、運用コストもかけたくない → Github Pages
  • DB使いたくないのでSSGが理想 → SveltekitでSSG
  • SSGなら、定期的にビルドがいる → Github actions
  • 画面の動的要素は最低限でよく、読み込み速度優先でよい → JS 無効化、必要なら Svelte

Sveltekit ではなく Astro にしていればもっと最適化の余地がありそうですが、まあ誤差と言ってもいいでしょう。

RSS を収集する

今回の肝。たぶん

rss-parser を利用しました。

https://www.npmjs.com/package/rss-parser

このあたり苦労する想定でいたのですが、やってみたらなんと一瞬だったという驚き。

const parser = new Parser({});
const feed = parser.parseURL(url);

これだけで feed にしっかり typescript の型が付いたオブジェクトが格納されます。
あとは全サイトまとめて日付でソートするだけです。

イメージ:

export const FEED_LENGTH = 20;

export const feedTargets: string[] = [
	'https://example.com/rss',
	'https://example2.com/rss',
];

/***************************************************/

/**
 * items配列にサイト名を含めたりタイムスタンプをDate型変換する
 */
const convertFeed = (feed: Parser.Output<unknown>) => {
	return feed.items.slice(0, FEED_LENGTH).map((x) => ({
		...x,
		timestamp: new Date(x.isoDate ?? x.pubDate ?? 0),
		blogTitle: feed.title
	}));
};

/***************************************************/

const parser = new Parser({});

// まとめてフェッチ
const feeds = await Promise.all(feedTargets.map((url) => parser.parseURL(url)));

// 整形,整列
const flatFeeds = feeds.feeds
	.flatMap((x) => convertFeed(x))
	.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());

細かい実装例は github のコードをご参照ください。

これを生成AIに「画面に並べろ」と指示するなりして表示したら完成!

Github Pages の設定

やることは2点。

  • プロジェクト内の Setting > Page から Github Pages をアクションからのデプロイに設定
  • actions 内で actions/upload-pages-artifact@v3 と actions/deploy-pages@v4 を使ってアップロード準備とデプロイ実行

actions の例は ↓ とかにあります。

https://kit.svelte.jp/docs/adapter-static#github-pages

あとがき

これの実装にかかったのは数時間ぐらいなのですが、

  • rss の収集
  • github actions の設定
  • github pages の設定
  • JAM Stack 構成に関する設計や挙動

の知見や経験が得られたのでお得でした。

Actions や Pages に慣れられたのはとてもよかったので、他のPJでも活用していきたいですね。

Discussion