本サイトは 2023 年の 2 月にリニューアル公開しましたが1、フレームワークには Astro を使用しています。このリニューアル直前の 1 月 24 日に Astro 2.0 がリリースされたのですが2、早くも 8 月 30 日に Astro 3.0 がリリースされました。

この記事では、本サイトにおける Astro 2.x から 3.0 へのアップグレードにともない、変更した箇所や注意点などを記述していきます。

Astro 公式のプレスリリースは以下です。

ハイライトとしては、以下の 6 点が挙げられています。

  1. View Transitions API をサポート
  2. 画像最適化が安定版に
  3. レンダリングのパフォーマンス向上(30-75% 高速)
  4. サーバレス向けの SSR 機能強化
  5. JSX の Hot Module Reloading(HMR)機能強化
  6. ビルド時に出力されるコード(HTML、CSS)の最適化

「1」「4」「5」については、この記事では取り扱いません。ただ、View Transitions API については、別途記事を作成できればと考えています。

なお、Astro 3.0 へのアップグレードはガイドに従い進めます。

変更箇所が多岐にわたるため、すべては紹介できませんが、本サイトの移行で調整が必要だった点や、興味深い点をいくつかピックアップします。

Astro 3.0 では Node 18.14.1 以上が必須条件なので、インストールされているバージョンを確認し、必要に応じてアップデートします。

node -v

そのうえで Astro 本体を 3.0 にアップグレードしますが、あわせて Astro のプラグインも最新バージョンにするのがよいでしょう。

Astro 2.x までは、props で渡した値を class に指定するには、class:list デイレクティブの new Set([]) で渡すことがありましたが、Astro 3.0 からは配列 [] のみになります。

class:list デイレクティブの例
---
const { columns = '3' } = Astro.props;
---
<!-- Astro 2.x -->
<ul class:list={['blog-list', new Set(['--columns-' + columns])]}>...</ul>

<!-- Astro 3.0 -->
<ul class:list={['blog-list', ['--columns-' + columns]]}>...</ul>

廃止: Markdown の下書き機能

見出し「廃止: Markdown の下書き機能」

Astro 2.x までは、Markdown や MDX の Front Matter に draft: true と指定することで、開発モードでは出力され、ビルド時ではファイルが出力されないといったことが可能でした。

下書き状態の MDX ファイルの例
---
draft: true
---

Astro 3.0 からは、この機能が使えなくなりますが、テンプレート側でフィルタリングすることで同様の機能を実現できます。

下書きの記事を除外する例
---
import { getCollection } from 'astro:content';

const blogEntries = await getCollection('blog', ({ data }) => {
  return import.meta.env.PROD ? data.draft !== true : true;
});
---

ローカル環境で Astro を立ち上げたときの、デフォルトのポート番号が 3000 から 4321 に変わります。

# Astro 2.x
localhost:3000

# Astro 3.0
localhost:4321

多くのフレームワークではデフォルトのポート番号が 3000 のため、同時に立ち上げていると競合することがあるので理にかなった変更といえます。また「Astro」だけに、カウントダウンを想起させる 4321 🚀 なのもユーモアがあり覚えやすいです。

Astro 2.x までは、出力される HTML を圧縮するには、設定ファイル(astro.config.mjs)に明示する必要がありましたが、Astro 3.0 からはデフォルトで圧縮化されるようになりました。

変更: スタイルのスコープ

見出し「変更: スタイルのスコープ」

Astro ではコンポーネントのファイルごとにスタイルのスコープが閉じ込められますが、Astro 2.x までは、そのセレクタが class 属性でした。Astro 3.0 からは data-* 属性に変わります。

例えば、以下のような Astro コンポーネントがあるとします。

Astro コンポーネントの例
---
---
<a href="/blog/" class="btn">ブログ</a>

<style>
.btn {
  padding: 10px;
}
a {
  text-decoration: none;
}
</style>

Astro 2.x までは以下のような HTML と CSS が生成されていました。

Astro 2.x で生成される HTML ファイル
<a href="/blog/" class="btn astro-37FXCHFA">ブログ</a>
Astro 2.x で生成される CSS ファイル
.btn:where(.astro-37FXCHFA) {
  padding: 10px;
}
a:where(.astro-37FXCHFA) {
  text-decoration: none;
}

Astro 3.0 からは data-* 属性に変わります。

Astro 3.0 で生成される HTML ファイル
<a href="/blog/" class="btn" data-astro-cid-37FXCHFA>ブログ</a>
Astro 3.0 で生成される CSS ファイル
.btn[data-astro-cid-37FXCHFA] {
  padding: 10px;
}
a[data-astro-cid-37FXCHFA] {
  text-decoration: none;
}

まず、CSS の詳細度が 0-1-0 から 0-2-0 に上がるため、:global でグローバルスタイルを指定していると、スタイルの優先度が入れ替わる可能性があります。

また、これはレアケースですが、この class 属性を操作している場合には調整が必要になります。

本サイト内のプロジェクト「RECTBEATS」と「RECTGRAPH」では、SVG ファイルを生成してダウンロードするときに、SVG ファイルのサイズを削減する目的で、この astro- 接頭辞の class 属性を削除していました。

このスタイルのスコープの変更により、class 属性から data-astro-cid-* を削除するようにチューニングする必要がありました。

なお、設定ファイル(astro.config.mjs)に明示することで、これまでの class 属性の指定を維持することも可能です。

変更: インラインスタイルシート

見出し「変更: インラインスタイルシート」

Astro 2.x では、デフォルトでスタイルシートは <link> 要素で読み込まれていましたが、Astro 3.0 では合理的なサイズまでは <style> 要素でのインラインスタイルシートが指定されるようになりました3

ほとんどのケースでは問題ないかと思いますが、HTTP ヘッダで Content Security Poilcy(CSP)を指定している場合には、style-src のポリシーに抵触する可能性があります4

こちらも、設定ファイル(astro.config.mjs)に明示することで、インラインスタイルシートを拒否することができます。

削除: getStaticPaths() の戻り値を自動的にフラット化

見出し「削除: getStaticPaths() の戻り値を自動的にフラット化」

Astro 2.x までは、getStaticPaths() の戻り値の配列を自動的にフラット化してくれていましたが、Astro 3.0 からはこの処理が削除されました。

そのため、入れ子になっている配列が残っていると以下のようなエラーが表示されます。

InvalidGetStaticPathsEntry: Invalid entry returned by getStaticPaths. Expected an object, got array

本サイトにおいては、ブログのタグページでこのエラーが発生しましたが、map()flatMap() に変更することで解消しました。

待望の画像最適化が安定版になりましたが、提供される機能は最低限にとどまります。

この画像最適化の機能は、widthheightloading といった属性の自動追加や、WebP への変換、ファイルサイズの削減といったレベルにとどまり、<picture> 要素や srcsetsizes 属性を使用したレスポンシブイメージは基本機能としては用意されていません。

本サイト内で画像を使用しているのはブログ記事の MDX ファイルがメインです。<Image /> コンポーネントを使用した指定の場合、画像ファイルを import しなければならず、点数が多い場合には煩雑に感じます。

MDX で複数の画像を表示する例
---
---
import { Image } from 'astro:assets';

import image1 from '../assets/image1.png';
import image2 from '../assets/image2.png';
import image3 from '../assets/image3.png';

<Image src={image1} alt="画像 1" />
<Image src={image2} alt="画像 2" />
<Image src={image3} alt="画像 3" />

このビルトインの <Image /> により、widthheight を指定したり、WebP に変換する手間は減らせますが、もう少し効率的な指定方法を考えつつ、ひとまず導入は見合わせます。

この記事では、本サイトにおける Astro 2.x から 3.0 への移行について説明しました。

いくつか新機能も追加されましたが、ここで取り上げたように改廃された機能も多く、パフォーマンスの向上にかなり力を入れているように感じました。

ハイライトで取り上げた機能の多くは試せていませんが、View Transitions API や画像最適化については、引き続き使用方法を考えていきます。

もし、本サイトの不具合などお気づきの点がございましたらお知らせください。

脚注

  1. ウェブサイトをリニューアルしました | grip on minds

  2. Astro 2.0

  3. インラインスタイルシートのファイルサイズの上限は、ViteConfig.build.assetsInlineLimit の 4kb(4096)がデフォルトのようです(Build Options | Vite)。

  4. CSP: style-src | MDN