// A devlog by mood.

Astro6に上げたら記事が空になった

Astro6アップデート後に出たcontent collectionsエラーと、実際に直したコードのメモ。

Astro6に上げたあと、ビルドでこんなエラーが出ました。

The collection "posts" does not exist or is empty.
Please check your content config file for errors.

原因はcontent collectionsの扱いが変わっていたことでした。

何が変わっていたか

  • 旧来のtype: 'content'だけの定義では足りず、loaderが必要だった
  • post.slug前提のコードがv6ではそのまま使えなかった

変更したコード

まずは src/content.config.ts
ここを glob() を使う形に変更しました。

// before
import { defineCollection, z } from 'astro:content';

const posts = defineCollection({
  type: 'content',

  schema: z.object({
    title: z.string(),
    description: z.string(),
    ogImage: z.string().optional(),
    publishedAt: z.coerce.date(),
    draft: z.boolean().optional().default(false),
  }),
});

export const collections = {
  posts,
};

// after
import { defineCollection } from 'astro:content';
import { glob } from 'astro/loaders';
import { z } from 'astro/zod';

const posts = defineCollection({
  loader: glob({
    pattern: '**/[^_]*.{md,mdx}',
    base: './src/content/posts',
  }),
  schema: z.object({
    title: z.string(),
    description: z.string(),
    ogImage: z.string().optional(),
    publishedAt: z.coerce.date(),
    draft: z.boolean().optional().default(false),
  }),
});

これでpostsコレクションの読み込み元をAstroにちゃんと伝えられるようになりました。
z のimportもastro/zodに変更しています。

次にpost.slugを使っていた部分。
今回はpost.idから URL用の文字列を作るようにしました。

export const getPostSlug = (post: PostEntry): string => {
  return post.id.replace(/\.(md|mdx)$/, '');
};

これを使って、詳細ページや関連記事のリンクを組み立てるように変更。

return posts.map((post) => ({
  params: { slug: getPostSlug(post) },
  props: {
    post,
    relatedPosts: pickRandomPosts(posts, getPostSlug(post), 3),
  },
}));

一覧側のリンクも同じです。

<a href={`/posts/${getPostSlug(post)}/`}></a>

直したあと

修正後はastro checkastro buildも通るようになりました。

メジャーアップデートって、やっぱり何かしらこういった変更が入ることがありますね。
依存更新自体はすぐ終わっても、こういうところで少しハマります。

同じエラーに当たったら、

  • content.config.ts がv6の形になっているか
  • slug前提のコードが残っていないか

このあたりを見ると早そうです。 あと、公式ドキュメントはちゃんと読んだほうが早いっすね。

以上、おわり。