EY-Office ブログ

AstroをContent Collectionsに対応しIncremental Content Cachingを試してみました

前々回のブログ で、「Astro4.0のIncremental Content Caching (Experimental)を試したけど、わずかにしか早くならなかった」と書きました。その原因は、この機能はAstro V2で導入されたコンテンツコレクション(Content Collections)に依存しているからでした。

EY-OfficeサイトはAstro V1ベースで作られていたので、コンテンツコレクション に対応し Incremental Content Caching (Experimental)を試したところ、確かに高速化されました!

Astro

コンテンツコレクション(Content Collections)への対応

コンテンツコレクションは、ブログ等のコンテンツの集まりを効率的に管理するための機能でです。

コンテンツコレクションへの対応は公式ドキュメントのファイルベースのルーティングからの移行に書かれています。

移行手順は、

  1. Astro V2以降にバージョンアップ
  2. コレクションをsrc/content/ディレクトリーに移動
  3. コンテンツタイプのスキーマを定義 src/content/config.ts
  4. コレクションの取得APIをAstro.glob()からgetCollection()に変更

ブログ管理ライブラリーの変更

EY-Officeサイトのブログを管理するために、BlogPost.tsというモジュールを書いています。機能は、一覧の取得、最新ブログ、前ブログ、次ブログの取得、カテゴリー別の取得などです。

現バージョンのBlogPost.tsの一部
  • ① このモジュールが読み込まれた時点で import.meta.glob (Astro.globと同じ機能)を使い、全ブログを読み込みす
    • postImportResultは{ブログパス名:ブログ内容}のオブジェクトなので値を取り出し、並びを逆(最新を添字0)にしています
    • ブログ内容はposts配列に入ります
  • ② ここに並ぶ関数は、次ブログのリンク、前ブログのリンク、最新ブログの内容、カテゴリー別ブログの内容を取得するAPIです
    • これらのAPIはブログ記事ページやブログの右側のサイドバー、その他のページで使われています。
// ↓ ①
const postImportResult = import.meta.glob('../_blog/*/*.md', { eager: true });
const posts = Object.values(postImportResult).reverse() as MarkdownInstance<Record<string, any>>[];
console.log(`\n*** Blog count = ${posts.length}\n`);

// ↓ ②
export const nextPostLink = (ix: number): PostLinkType =>
  ix > 0 ? {title: posts[ix - 1].frontmatter.title, path: blogUrl(posts[ix - 1])} : null;

export const previousPostLink = (ix: number): PostLinkType =>
  ix < posts.length - 1 ? {title: posts[ix + 1].frontmatter.title, path: blogUrl(posts[ix + 1])} : null;

export const lastBlog = () => {
  return blogInfo(posts[0]);
};

export const categoryBlogs = (category: string) => {
  return posts.filter((post) => post.frontmatter.categories.includes(category)).
    map(post => blogInfo(post));
}
Content Collections対応バージョンのBlogPost.tsの一部
  • ① Content Collectionsからコンテンツの取得はgetCollection()APIを使うのですが、このAPIは非同期なのでgetAllBlogs()APIをトップページ表示のさいに呼び出してもらいposts配列にブログを格納します
  • ② したがって取得APIは、変更なしです
// ↓ ①
let posts: CollectionEntry<"blog">[] = [];

export const getAllBlogs = async() => {
  if (posts.length === 0) {
    console.trace();
    posts = await getCollection("blog");
    posts.reverse();
     console.log(`\n*** Blog count = ${posts.length}\n`);
  }
}

// ↓ ②
export const nextPostLink = (ix: number): PostLinkType =>
  ix > 0 ? {title: posts[ix - 1].frontmatter.title, path: blogUrl(posts[ix - 1])} : null;

export const previousPostLink = (ix: number): PostLinkType =>
  ix < posts.length - 1 ? {title: posts[ix + 1].frontmatter.title, path: blogUrl(posts[ix + 1])} : null;

export const lastBlog = () => {
  return blogInfo(posts[0]);
};

export const categoryBlogs = (category: string) => {
  return posts.filter((post) => post.frontmatter.categories.includes(category)).
    map(post => blogInfo(post));
}

このように小規模の変更でコンテンツコレクションに対応できました。

その他の変更

それ以外の変更点は以下です。

高速化されたのか?

はい、早くなりました。😃

JSCollectionsCachingビルド時間
Node.jsなしなし7.9 秒
Bunなしなし7.4 秒
Node.jsありなし10.1 秒
Bunありなし10.2 秒
Node.jsありあり6.2 秒
Bunありあり6.1 秒
  • Collections: Content Collections
  • Caching: Incremental Content Caching (Experimental)

今回はBunでの高速化はありませんでしたが、Incremental Content Caching を有効にすると40%近く早くなりました。

よいお年をお迎えください

今年も毎週ブログを書けました。たまにネタが無くて苦心した事もありましたが12月はAstroさんにネタを提供して頂きたすかりました。😃

皆さま、よいお年をお迎えください。

- about -

EY-Office代表取締役
・プログラマー
吉田裕美の
開発者向けブログ