SvelteKitでシンプルなRSSリーダーを作成する方法

RSSは、ウェブコンテンツを構造化された形式で配信するための一般的な標準です。テクノロジー愛好家から教師まで、多くの人がRSSを使って、お気に入りのブログの最新ニュースや投稿を把握しています。

Svelte上に構築されたメタフレームワークであるSvelteKitを使えば、独自のRSSリーダーを簡単に作成できます。

SvelteKitプロジェクトの設定

このプロジェクトで使用されているコードはGitHubリポジトリで入手でき、MITライセンスに基づいて自由に使用できます。このプロジェクトのライブバージョンを見たい場合は、このデモをご覧ください。

先に進む前に、マシンにNode.jsランタイムとNode Package Manager(NPM)がインストールされている必要があります。ターミナルを開いて、次のコマンドを実行します:

npm create svelte
# または
yarn create svelte

これにより、Viteを搭載したcreate-svelteコマンドラインインターフェイス(CLI)が起動します。プロジェクトに名前を付け、アプリのテンプレートを「スケルトン・プロジェクト」に設定します。TypeScriptによる型チェックを無効にし、必要な追加オプションを選択します。その後、プロジェクトディレクトリに移動して、次のコマンドを実行します:

npm install
# または
yarn

デフォルトの依存関係をインストールしたら、rss-parsermomentという2つのパッケージをインストールする必要があります。最初のパッケージはXMLデータの解析を容易にし、2番目のパッケージは日付を正しくフォーマットするのに役立ちます。ターミナルで、次を実行します:

npm install rss-parser
npm install moment
# または
yarn add rss-parser
yarn add moment

これで、次のコマンドを実行して開発サーバーを起動できます。

npm run dev
# または
yarn dev

App.cssファイルの内容をクリアし、プロジェクト構造を次のようなものに変更します。まだ存在しないディレクトリを作成し、以下に名前を付けたものと一致するように空のファイルを作成します:

srcディレクトリのみを変更する必要があります。このディレクトリにはlibディレクトリとlib/addToLocalStorage.jsファイルが含まれている必要があります。また、feedという名前の子ディレクトリと+layout.js+layout.svelte+page.svelte+server.jsという4つのファイルを含むroutesディレクトリも含まれている必要があります。feedの中に、[title]という名前のディレクトリを作成し、その中に+page.server.js+page.svelteという2つのファイルを作成します。

多くのシェルでは角括弧がパターンの照合に使用されるため、コマンドラインで[title]ディレクトリを作成するのは難しい場合があります。エラーが発生した場合は、ディレクトリ名を引用符で囲んでみてください。例:

mkdir '[title]'

有効なRSSフィードを確認するためのAPIルートの作成

routes/+server.jsファイルを開き、jsonユーティリティをインポートします。また、rss-parserパッケージからParserをインポートします。

import { json } from "@sveltejs/kit";
import Parser from "rss-parser";

次に、非同期関数GETをエクスポートし、urlをパラメータとして渡します。この関数の中で、rssLinkparserという2つの定数を作成します。

最初の定数は、渡されたurlから検索パラメータを保持する必要があります。2番目の定数parserは、新しいParserオブジェクトインスタンスを格納する必要があります。次に、parserparseURLメソッドを呼び出し、rssLinkをパラメータとして渡します。最後に、json関数でレスポンスをシリアル化して返します。

export async function GET({url}) {
const rssLink = url.searchParams.get('url');
const parser = new Parser();
let feed = await parser.parseURL(rssLink);
return json(feed);
}

ホームのデザイン

SvelteKitは、ファイルシステムベースのルーティングシステムを使用しています。デフォルトでは、routes/+page.svelteファイルがWebサイトのホームとして機能します。

+page.svelteファイルを開き、scriptタグでlibディレクトリからaddToLocalStorage関数をインポートします。まだ作成していませんが、後で作成します。関数をインポートした後、urlreadyという2つの変数を作成し、ready変数をfalseに設定します。

<script>
import addToLocalStorage from '$lib/addToLocalStorage';
let url;
let ready = false;
</script>

マークアップセクションに以下を追加します:

<main>
<h1>RSSリーダー</h1>
<h3>新しいフィードを追加:</h3>
<input
type="url"
placeholder="有効なRSSリンクを入力..."
bind:value={url}
on:input={() => {
if (url.length > 0) {
setTimeout(() => {
ready = true;
}, 250);
} else {
ready = false;
}
}}
/>
</main>

上記のコードブロックは、ユーザー入力の長さが0より大きい場合にready変数をtrueに設定するinput要素を定義しています。次に、readytruthyの場合にいくつかの要素をレンダリングするコードを追加します。

{#if ready}{#await fetch(/?url=${url}).then((res) => res.json())}情報を収集しています...お待ちください{:then data}{#if data.message === 'Internal Error'}エラーが発生しました...URLを確認して再試行してください{:else}{#if data.image}{/if}{data.title}{data.description || ''}{console.log(data) || ''}{addToLocalStorage(data.title, url);location.reload();}}>私のフィードに追加{/if}{/await}{/if}

このコードブロックは、readyがtruthyであるかどうかを確認し、その後、先ほど作成したAPIルートを呼び出します。このコードは、ユーザーが入力したURLが有効なRSSフィードを指しているかどうかを確認する役割を果たします。

最後に、ページの基本的なスタイルを次のように追加します:

<style>
img {
width: 40px;
height: 40px;
}
input {
padding: 15px;
font-size: 20px;
width: 50%;
}
</style>

レイアウトの設定

layout.jsファイルに次のコードを追加します。このコードは、Svelteに+layout.svelteファイルをクライアントでのみ実行するように指示します:

export const prerender = false;
export const ssr = false;

次に、+layout.svelteファイルで、ローカルストレージからフィードのリストを返します。

<script>
let feeds = JSON.parse(window.localStorage.getItem('feeds')) || [];
feeds = feeds.reverse();
</script>

次に、次のようなナビゲーションバーのマークアップを追加します:

ホーム私のフィード:{#each feeds as feed}{@const number = feeds.indexOf(feed)}{number + 1}. {feed.title}{/each}

slotコンポーネントとレイアウトのスタイルを追加します:

<slot />
<style>
nav {
display: flex;
font-size: 18px;
background-color: white;
padding: 10px;
width: 98vw;
}
.my-feeds {
display: flex;
white-space: nowrap;
overflow-x: scroll;
margin-left: 30px;
gap: 10px;
}
span {
white-space: nowrap;
font-weight: 900;
margin-left: 20px;
margin-right: -5px;
}
</style>

ローカルストレージに有効なURLを追加する

アプリがRSSフィードの存在を確認したら、そのURLをローカルストレージに保存するメカニズムを用意しておくと、ユーザーが再入力する必要がなくなります。addToLocalStorage.jsファイルを開き、次を追加します:

export default function addToLocalStorage (title, url) {
let feedInLocalStorage = JSON.parse(localStorage.getItem("feeds")) || [];
localStorage.setItem(
"feeds",
JSON.stringify([...feedInLocalStorage, {title:title, url:url}])
);
}

このコードは、localStoragesetItemメソッドを使用して、ユーザーのフィードに関するデータを含む配列をキャッシュします。

特定のRSSフィードのエントリリストをレンダリングする

[title]/+page.server.jsファイルに以下を追加します:

import Parser from "rss-parser";
export async function load({url}){
const rssLink = url.searchParams.get('url');
const parser = new Parser();
let feed = await parser.parseURL(rssLink);
return {...feed};
}

これは、+page.svelteファイルと並行して実行されるコードです。特定のフィードから最新のエントリを取得します。次に、+page.svelteファイルでmomentパッケージをインポートし、dataプロップを追加します:

<script>
import moment from 'moment';
export let data;
</script>

次に、利用可能な場合は画像をレンダリングし、data.items配列の各アイテムを走査して、適切なコンテンツをレンダリングします:

{#if data.items}
{#each data.items as item}
{@const number = data.items.indexOf(item)}
<div>
{number + 1}.
<a href={item.link}> {@html item.title}</a>
<div>
<span>{item.author || item.creator || ""}</span>
<span>{moment(item.isoDate).fromNow()}</span>
</div>
<div>{item.contentSnippet || ""}</div>
</div>
{/each}
{:else}
<p>エラーが発生しました...</p>
{/if}

最後に、ページを好きなようにスタイル設定します:

<style>
.snippet {
font-size: 18px;
}
a {
font-size: 25px;
text-decoration: underline;
color: black;
&:visited {
color: gray;
}
&:hover {
text-decoration: none;
}
}
.item {
display: flex;
flex-direction: column;
padding: 10px 10px;
}
.metadata {
display: flex;
gap: 10px;
margin: 10px 0px 10px 0px;
}
img {
width: 40px;
height: 40px;
}
</style>

これで、SvelteKitを使って非常にシンプルなRSSリーダーを作成することができました。

RSSはどのような用途に適しているか

複数のWebサイト、ブログ、ニュースソース、ポッドキャストを同時に扱っている場合、RSSはより整理された、時間効率の高い読書体験へのゲートウェイとなります。

RSSはコンテンツの収集やニュースの最新情報を入手するための素晴らしいツールですが、リアルタイムでインタラクティブな、高度なセキュリティを必要とする、または高度にパーソナライズされたコンテンツシナリオには適していないことに注意してください。