Deno の lume で外部のブログサービスから記事を取得して表示する

こんにちは。
Deno の lume で外部のブログサービスから記事を取得して表示する方法(このサイトのブログの作り方)について紹介します。

このサイトについて

このサイト(piginbeer.com)は Deno の lume で作ってます。
Deno だと SSG ができるフレームワークとして Aleph.js も有名かと思いますが、このサイトは単にプロフィールやブログなどを置くシンプルなサイトなのでより軽そうな lume を選びました。(Deno以外なら無限にあると思いますが)
ちなみに Deno Deploy でホスティングしています。

lume について

lume は ビルド時に色々な仕掛けが入れられる SSG フレームワークです。
本筋とは関係がありませんが、様々な Pluginsが提供されており、Webサイトの作成時によく使いそうな機能を簡単に追加していくことができ便利です。

記事を外部のブログからフェッチする

本題です。lumeの仕掛けを使って外部のブログのコンテンツをビルド時にフェッチし、それをコンテンツとして表示します。

事前にフェッチしてくる方法はいくつかありそうなのですが、自分が試した方法は2種類で実際に両方利用してました。
Shared Data を利用する方法とMultiple Pagesを利用する方法です。

Shared Data を利用する

lumeにはページ間で共有できるデータを記載できる Shared Dataという仕組みがあります。
_data.jsonなど _dataから始まるファイルを作り、その中で変数の定義を行うと、別のページファイルからそこで定義した変数を呼び出すことができます。
この Shared Data_data.tsなどスクリプトファイルとしても定義でき、ビルド時にスクリプトの評価が行われます。
fetch も呼び出すことができるので、外部ブログのapiなどを呼び出せばデータを取得できます。

下記にQiitaからデータを取得してくるサンプルを記載します。

const qiitaPostsResponse = await fetch(
  "https://qiita.com/api/v2/items?query=user:hyakt",
);
const posts = await qiitaPostsResponse.json();

export { posts };
_data.ts

呼び出し側ではこのスクリプトと同様のディレクトリで Page fileを作成します。

<div>
    {{ for post of posts }}
    <a href="{{ post.url }}" target="_blank">
        {{ post.title }}
    </a>
    {{ /for }}
</div>
index.vto

これでビルド時に QittaのAPIを呼び出し、Qiitaのデータを取得することができます。
こんな感じのリンク集などで問題ないのであればShared Data を使うのが良いと思います。

Multiple Pages を利用する

もう一つはMultiple Pagesを利用する方法です。
ページファイルを作るときに generator 関数を使うと、複数のページを生成することができます。
この中でも fetch を呼び出すことができるので、外部ブログのapiのレスポンスから複数のページを生成することができます。

export default async function*() {
  const qiitaPostsResponse = await fetch(
    "https://qiita.com/api/v2/items?query=user:hyakt",
  );
  const posts = await qiitaPostsResponse.json();

  for await (const post of posts) {
    yield {
      url: `/posts/${post.title}/`,
      title: post.title,
      content: post.body,
      tags: "post",
    };
  }
}
external.page.ts

その後、別のページ内で作成したページを search 関数で検索して表示してあげましょう。

<div>
  {{ for post of search.pages("post") }}
  <a href="{{ post.url }}" target="_blank">
    {{ post.title }}
  </a>
  {{ /for }}
</div>
index.vto

これでビルド時に外部リソースから取得した内容でからページを生成することができます。
Multiple Pages のメリットとしては自前でページを持てるので、自身のブログのように扱えるようになることと思います。

終わりに

この記事では、Deno の lume を使って外部のブログサービスから記事を取得し、表示する方法について紹介しました。主に2つの方法を説明しました:

  1. Shared Data を利用する方法:

    • _data.ts ファイルでデータをフェッチし、他のページで使用する
    • リンク集などのシンプルな表示に適している
  2. Multiple Pages を利用する方法:

    • ページファイルで generator 関数を使い、外部データから複数のページを生成する
    • 自前のブログページのように扱える利点がある

どちらの方法も、lume の機能を活用して外部コンテンツを効果的に取り込み、表示することができます。

モチベーション的な話をすると、今回自分のサイトを作るとき、記事は外部のブログサービスで書くのが良いと考え自前でブログを作るのはやめときました。
ただ、実績的な部分として自分のページに載せたかったので、1.の方法で書いた記事をサイトに集約する形を思いつきました。

今はなんだかんだ書き殴りたいこともあるかー、自前で適当にを持つかーという気持ちになり、2.の方法でサイト上でも自前で書けるようにしました。