BLOG

Astroで最新記事から日付順に記事一覧を表示する

Written by mizuishi

INDEX

こんにちは、mizuishiです。

今回は、Astroで最新記事から日付順に記事一覧を表示する方法をご紹介します。

Astroとは

以前の記事にもありますが、Astroとはコンテンツにフォーカスした高速なWebサイトを構築するためのオールインワンWebフレームワークです。

主に以下のような特徴があります。

  • 静的サイトジェネレーターとしても使える
  • ビルド後の出力ファイルからJavaScriptが取り除かれる
  • ビルドツールにViteを採用しているので開発体験がとても良い
  • 公式ドキュメントが日本語対応しているので情報のキャッチアップが容易

この記事を読んでAstroに興味を持った方、またこの記事を読む前にAstroの基礎知識を知りたい方は公式ドキュメントをご覧ください。

最新記事から日付順に記事一覧を表示

Astro では、Markdown ファイルの Frontmatter から日付情報を取得して記事一覧を生成することができます。

その方法を順を追って説明していきます。

1. 記事一覧を取得する

まず、コードフェンス(---)内に、以下のように Astro.glob()を使用して、記事一覧を取得します。

const allPosts = await Astro.glob("../pages/posts/_.md");
const nonDraftPosts = allPosts.filter((post) => !post.frontmatter.draft);

このコードでは、Astro.glob()を使用して、../pages/posts/_.md にマッチする Markdown ファイルのリストを取得しています。

filter()を使用して、drafttrue でない記事のみを取得しています。

draftは下書きのものです。

2. 日付順にソートする

次に、記事を日付順にソートします。

以下のように、sort()メソッドを使用して、pubDate の値に基づいて記事を並び替えます。

const allPosts = await Astro.glob("../pages/posts/_.md");
const nonDraftPosts = allPosts.filter((post) => !post.frontmatter.draft);

// ↓追加↓
const sortedPosts = nonDraftPosts.sort((a, b) => {
  const aDate = new Date(a.frontmatter.pubDate);
  const bDate = new Date(b.frontmatter.pubDate);
  return bDate - aDate;
});

ただ、このコードでは「算術演算の右辺には、'any' 型、'number' 型、'bigint' 型、または列挙型を指定する必要があります。」と

エラーが出てしまいます。

このエラーは、比較する値の型が不明確なために発生しているようです。

Date()オブジェクトは関数として呼び出された場合、現在の日付と時刻の文字列表現を返すため、a.frontmatter.pubDateb.frontmatter.pubDate に、比較演算子 < および > を使用することができません。

Date - JavaScript | MDN

この問題を解決するために、 new Date()を用いて文字列を日付オブジェクトに変換した後、getTime()で日付オブジェクトのミリ秒数を取得する必要があります。

■例

const dateTest = new Date();

// new Date()のみの場合
console.log(dateTest); // 2023-05-17T15:00:00.000Z

// getTime()を用いた場合
console.log(dateTest.getTime()); // 1684335600000

Date.prototype.getTime() - JavaScript | MDN

上記の例のようにgetTime()で日付オブジェクトのミリ秒数を取得できるので、それらの差を計算することで解決できます。

const allPosts = await Astro.glob("../pages/posts/_.md");
const nonDraftPosts = allPosts.filter((post) => !post.frontmatter.draft);

// ↓削除↓
// const sortedPosts = nonDraftPosts.sort((a, b) => {
//   const aDate = new Date(a.frontmatter.pubDate);
//   const bDate = new Date(b.frontmatter.pubDate);
//   return bDate - aDate;
// });

// ↓以下のコードに変更↓
const sortedPosts = nonDraftPosts.sort((a, b) => {
  const aDate = new Date(a.frontmatter.pubDate);
  const bDate = new Date(b.frontmatter.pubDate);
  return bDate.getTime() - aDate.getTime();
});

そうすることで、

../pages/posts/sample1.md

---
layout: ../layouts/BaseLayout.astro
title: Sample 1
pubDate: 2023-08-01
draft: false
---
## タイトル1

テキストテキストテキストテキストテキストテキスト

../pages/posts/sample2.md

---
layout: ../layouts/BaseLayout.astro
title: Sample 2
pubDate: 2023-08-02
draft: true
---
## タイトル2

テキストテキストテキストテキストテキストテキスト

../pages/posts/sample3.md

---
layout: ../layouts/BaseLayout.astro
title: Sample 3
pubDate: 2023-08-03
draft: false
---
## タイトル3

テキストテキストテキストテキストテキストテキスト

のようなMarkdown ファイルが合った場合、記事一覧ページでは

・sample3

・sample1

の順で表示されるようになります。

3. 記事一覧を表示する

最後に、以下のようにmap()を使用して、画面に記事一覧を表示します。

---
const allPosts = await Astro.glob("../pages/posts/_.md");
const nonDraftPosts = allPosts.filter((post) => !post.frontmatter.draft);
const sortedPosts = nonDraftPosts.sort((a, b) => {
  const aDate = new Date(a.frontmatter.pubDate);
  const bDate = new Date(b.frontmatter.pubDate);
  return bDate.getTime() - aDate.getTime();
});
---

// ↓map()を使用して、記事一覧を表示↓
<ul>
  {sortedPosts.map((post) => (
    <Post
      url={post.url}
      title={post.frontmatter.title}
      pubDate={post.frontmatter.pubDate}
      tags={post.frontmatter.tags}
    />
  ))}
</ul>

このコードでは、sortedPosts の各記事に対して、<Post>コンポーネントを使用して、リストアイテムを生成します。

これにより、Astro で最新記事から日付順に記事一覧を表示することが出来ました。

古い記事から表示したい場合

もし、古い記事から表示したい場合は以下のようにbDate.getTime() - aDate.getTime();aDate.getTime() - bDate.getTime();とすることで実現出来ます。

---
const allPosts = await Astro.glob("../pages/posts/_.md");
const nonDraftPosts = allPosts.filter((post) => !post.frontmatter.draft);
const sortedPosts = nonDraftPosts.sort((a, b) => {
  const aDate = new Date(a.frontmatter.pubDate);
  const bDate = new Date(b.frontmatter.pubDate);

//  return bDate.getTime() - aDate.getTime();

// ↓以下に変更↓
  return aDate.getTime() - bDate.getTime();
});
---
<ul>
  {sortedPosts.map((post) => (
    <Post
      url={post.url}
      title={post.frontmatter.title}
      pubDate={post.frontmatter.pubDate}
      tags={post.frontmatter.tags}
    />
  ))}
</ul>

最後に

以上で、Astro で最新記事から日付順に記事一覧を表示する方法を説明しました。

より使いやすく魅力的なブログを作成してください。

参考

https://docs.astro.build/ja/tutorial/5-astro-api/1/

https://route360.dev/ja/post/astro-prevnext-posts/

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date/getTime