Astroをv5に上げた

## この記事の概要

私は[自分のポートフォリオサイト](https://www.keisukewatanuki.work/)を[Astro](https://astro.build/)で作っています。

いるでのすが、v4が出たときにバージョンを上げるのをサボってしまっていました。

さすがにこれ以上アップデートに遅れが出ると問題だと思い、v3からv5に上げました。
備忘録がてらそのときの記録を記事にしています。

:::note warn
v3からv5に上げるからこその面白いハマりポイントでもあれば良かったのですが、特にありませんでした。
おそらくv4からv5に上げたとしてもほぼ同じ対応になっていたと思われます。
:::

## 環境

|  | Before | After |
| --- | --- | --- |
| Astroのバージョン | 3.3.0 | 5.0.3 |

## パッケージ自体のアップデート

[公式のマイグレーションガイド](https://docs.astro.build/en/guides/upgrade-to/v5/)に従います。
下記のコマンドを叩けば、Astro本体だけでなく公式のインテグレーションも一緒にアップデートしてくれます。

```sh
npx @astrojs/upgrade
# or
yarn dlx @astrojs/upgrade
#or
pnpm dlx @astrojs/upgrade
```

私の場合は[Tailwind CSSのインテグレーション](https://docs.astro.build/en/guides/integrations-guide/tailwind/)が該当しました。

```sh
 astro   Integration upgrade in progress.

      ●  @astrojs/tailwind will be updated to v5.1.3
      ▲  astro will be updated to  v5.0.3 

  wait   One package has breaking changes. Continue?
         Yes

 check   Be sure to follow the CHANGELOG.
         astro https://docs.astro.build/en/guides/upgrade-to/v5/

 ██████  Installing dependencies with pnpm...

╭─────╮  Houston:
│ ◠ ◡ ◠  Good luck out there.
╰─────╯
```

## Content collectionsの修正 1

開発環境を立ち上げて最初に出たエラーはこちらです。

```sh
[InvalidContentEntryDataError] DIRECTORY_NAME → ARTICLE_SLUG data does not match collection schema.
Cover image must be at least 1080 pixels wide!
  Hint:
    See https://docs.astro.build/en/guides/content-collections/ for more information on content schemas.
  Error reference:
    https://docs.astro.build/en/reference/errors/invalid-content-entry-data-error/
  Location:
    /Users/keisukewatanuki/Repositories/portfolio/src/content/works/figma-introduction-to-design/index.md:0:0
  Stack trace:
    at ...
```

もともと、スキーマを以下のように定義していました。

```typescript:src/content/config.ts
const someCollection = defineCollection({
  type: "content",
  schema: ({ image }) =>
    z.object({
      title: z.string(),
      cover: image().refine((img) => img.width >= 1080, {
        message: "Cover image must be at least 1080 pixels wide!",
      }),
      keywords: z.string().array(),
      startDate: z.coerce.date(),
      endDate: z.coerce.date().optional(),
      excerpt: z.string(),
    }),
});
```

しかし、v5へのアップデートで`image().refine()`が使えなくなったようです。

> `image().refine()` is not supported. If you need to validate the properties of an image you will need to do this at runtime in your page or component.

https://docs.astro.build/en/guides/upgrade-to/v5/#breaking-changes-to-legacy-content-and-data-collections

次のように変更することで対応できました。

バリデーションはできなくなってしまいましたが、カバー画像にうっかりサイズの小さい画像を設定してしまったときに気付くためだけのものなので、単純に削除で良しとします。

```diff_typescript:src/content/config.ts
  const someCollection = defineCollection({
    type: "content",
    schema: ({ image }) =>
      z.object({
        title: z.string(),
-       cover: image().refine((img) => img.width >= 1080, {
-         message: "Cover image must be at least 1080 pixels wide!",
-       }),
+       cover: image(),
        keywords: z.string().array(),
        startDate: z.coerce.date(),
        endDate: z.coerce.date().optional(),
        excerpt: z.string(),
      }),
  });
```

## Content collectionsの修正 2

上記の修正だけでもContent collectionsの問題は解消できましたが、現状の書き方はレガシー扱いになってしまったようです。
Content Layer APIを使った新しい書き方に直しておきます。

https://docs.astro.build/en/guides/upgrade-to/v5/#updating-existing-collections

このセクションに書いてある通りでほぼOKです。

自分が少しハマってしまった点としては`params: { slug: post.slug },`を`params: { id: post.id }`に修正するにあたり、ファイル名を`[slug].astro`のままにしてしまっていたことです。
ファイル名もあわせて`[id].astro`にする必要があります。

## `ViewTransitions`コンポーネントを`ClientRouter`コンポーネントに置換

deprecatedになっただけでまだ使えましたが、今のうちに置き換えました。

https://docs.astro.build/en/guides/upgrade-to/v5/#renamed-viewtransitions--component

## `src/env.d.ts`の削除と`tsconfig.json`の更新

`src/env.d.ts`の代わりに`.astro/types.d.ts`を使うようになったそうなので、ファイルを削除しました。
また、それにあわせて`tsconfig.json`も更新しています。

https://docs.astro.build/en/guides/upgrade-to/v5/#changed-typescript-configuration

https://docs.astro.build/en/guides/typescript/#tsconfig-templates

## まとめ

v3からv5だからとて、特別な何かにハマることもありませんでした……。
おそらく、v4からv5に上げたとしても同じような対応をしたと思います。

基本的にドキュメントが丁寧なので、書いてある通りに対応すればほぼすべて完了できて良かったです。