Astro 7.0リリース、Rustコンパイラでビルド時間を最大61%短縮

Astro 7.0リリース、Rustコンパイラでビルド時間を最大61%短縮

Astro 7.0リリース、Rustコンパイラでビルド時間を最大61%短縮

Astro 7.0が6月22日に正式リリースされた。今回のメジャーアップデートは「速度」にフォーカスしており、.astroファイルのコンパイラをRustで書き直した点が最大の変更点だ。

ベンチマークによると、ビルド時間は前バージョンと比較して15〜61%短縮される。Astro公式ブログが公開したテスト結果では、13,275ページを持つaspire.devのビルドが半分以下になった事例も報告されている。Rust化された基盤、Vite 8との統合、新しいアドバンストルーティング機能が主要な柱だ。

本記事ではAstro 7.0の全変更点を、実務者の視点から詳しく解説する。

Vite 8によるバンドル基盤の刷新

Vite 8によるバンドル基盤の刷新

Astro 7.0のビルド高速化を支える土台が、Vite 8へのアップグレードだ。Vite 8は、JavaScriptツールチェインの世界で最も注目されているリリースのひとつである。最大の変更点は、Rustベースのバンドラ「Rolldown」が標準搭載されたことだ。

Rolldownとは何か

Rolldownは、従来のesbuildとRollupを単一のバンドラで置き換えるツールである。バンドラとは、複数のJavaScriptファイルやコンポーネントを本番用の少数のファイルにまとめる役割を持つ。Rolldownのベンチマークでは、Rollupと比較して10〜30倍高速という結果が出ている。速度だけでなく、既存のRollupプラグインAPIとの互換性も維持している点が実務上の大きな利点だ。

Astroユーザーにとって重要なのは、ほとんどのプロジェクトで設定変更が不要なことだ。Vite 8には既存のesbuild設定やrollupOptions設定を自動的にRolldown用に変換する互換レイヤーが組み込まれている。カスタムViteプラグインを使っている場合も、RolldownがRollupと同じプラグインAPIをサポートするため、そのまま動作する可能性が高い。

Rust化がもたらすビルド性能の飛躍的向上

Rust化がもたらすビルド性能の飛躍的向上

Astroのビルドプロセスは、大きく2つの段階に分かれる。1つ目はサイトのページやコンテンツ、クライアントコンポーネントをJavaScriptにバンドルする段階。2つ目は、バンドルされたコードを「小さなサーバー」として実行し、プリレンダリング対象の全ページにリクエストを送ってHTMLを生成する段階だ。

Astro 7.0は両方の段階を改善しているが、とくに1つ目のバンドル段階に注力している。ビルド時間のボトルネックになりやすい処理をRustで書かれたネイティブコードに移行することで、大幅な高速化を実現した。

Astro 6.x のビルドフロー
.astro ファイル Go製 コンパイラ unified (Markdown処理) Recursive レンダリング
Markdown処理はJavaScriptベースで数千ページ規模だと大きなボトルネックに
Astro 7.0 のビルドフロー
.astro ファイル Rust製 コンパイラ (oxc/Lightning CSS) Sätteri (Rust製Markdown処理) キュー型レンダリング
Rust化+Vite 8 (Rolldown) の組み合わせで15〜61%のビルド時間短縮

上図の通り、ビルドフローの主要な構成要素がRustベースに置き換えられている。.astroファイルのコンパイル、Markdown/MDXの処理、レンダリングエンジンのすべてが刷新された。以下では各要素を詳しく見ていく。

.astroコンパイラのRust化

Astro 7.0では、.astroコンポーネント形式の新しいコンパイラがRustで構築された。このコンパイラは、以前のGoベースのコンパイラをフルリライトしたものだ。内部的には、oxc(高速なJavaScript/TypeScriptパーサ)を解析に、Lightning CSSをCSSスコープ処理に使っている。

単体ではビルド時間の約6%改善にとどまるが、数千ページ規模の大規模サイトでは、他の改善と相乗効果を発揮する。以下の3点は後方互換性に関わる変更として注意が必要だ。

  • HTML自動修正の廃止。旧コンパイラは「正しいHTML」にしようと要素の並べ替えやタグの自動クローズを行っていたが、新コンパイラではマークアップをそのまま扱う。予期せぬ挙動の原因だった自動修正がなくなり、意図した通りに出力されるようになった。
  • JSX形式の厳格化<div>Helloのような閉じタグ欠落や、<div class="Hello >のような属性の未終端は、自動修正されずエラーになる。旧コンパイラがブラウザの挙動を真似て黙って修正していた部分だ。
  • JSXホワイトスペース処理。インライン要素間の改行が可視スペースを生成しなくなる。たとえば、<span>Hello</span><span>World</span>は「HelloWorld」と表示される。スペースが必要な場合は{' '}を明示的に挿入する。

Markdown/MDX処理のSätteri移行

Astro 7.0では、デフォルトのMarkdownとMDXの処理パイプラインが、Rust製プロセッサ「Sätteri」に置き換えられた。SätteriはAstroコアチームメンバーが開発したツールで、内部的にはpulldown-cmark(CommonMark解析)とoxc(MDX式解析)を使用している。

従来のAstroは、JavaScriptベースのunified(remark/rehypeとそのプラグイン群)でMarkdownを処理していた。数千ページのサイトでは、このパイプラインがビルドの最も遅い段階になることが多かった。Astro公式ブログによれば、AstroドキュメントサイトとCloudflareドキュメントサイトでSätteriに切り替えたところ、ビルド時間が1分以上短縮されたという。

Sätteriには、これまで別途プラグインが必要だったMarkdown機能の多くがビルトインで含まれている。GFM(テーブル、脚注、取り消し線、タスクリスト)、スマートパンクチュエーション(カーリークォート)、見出しID、コンテナディレクティブ、数式、フロントマター(YAML/TOML)、上付き・下付き文字、Wikilinksなどだ。これらはfeaturesオプションで有効化できる。

既存のremark/rehypeプラグインに依存しているプロジェクトは、@astrojs/markdown-remarkを使って従来のunifiedベースのパイプラインを引き続き利用できる。

キュー型レンダリングの安定化

Astro 6.0で実験的機能として導入されたキュー型レンダリングが、Astro 7.0で安定版となりデフォルトのレンダリングエンジンになった。これは、式が密集したページで約2.4倍高速という結果が出ている。

従来のレンダリングは再帰的アプローチを取っていた。親コンポーネントが子コンポーネントを呼び出し、さらにその子が孫を呼び出すという入れ子構造でレンダリングが進む。これに対し、新しいエンジンはキュー(またはスタック)と単一のループを使う。キューに子ノードを正しい順序で追加し、キューが空になるまでループでレンダリングを続ける仕組みだ。

初回の実装では「全コンポーネントの順序付きリストを作成→リストをループしてレンダリング」という2パス方式だったが、最終版ではリスト作成とレンダリングを同時に行う方式に改善された。この方式は再帰的アプローチと比較してメモリ使用量も少ない。

アドバンストルーティングでリクエストパイプラインを完全制御

アドバンストルーティングでリクエストパイプラインを完全制御

Astroは静的サイトジェネレーターとしてスタートし、ファイルベースのルーティングを基本としてきた。しかし、ミドルウェア、リダイレクト、リライト、Actions、セッション、i18nといった機能が追加されるにつれ、リクエストのライフサイクル制御が複雑化していた。

認証をActionsより先に実行したい、ログ出力をページレンダリングだけに限定したい、APIリクエストをAstroの外で先に処理したい、といったニーズに応えるため、Astro 7.0ではsrc/fetch.tsファイルを追加することでリクエストパイプラインを完全制御できるようになった。

このパターンは、Cloudflare WorkersやDeno、Bunが採用している標準的なfetchハンドラ形式に準拠している。

import { astro, FetchState } from 'astro/fetch';

export default {
  fetch(request: Request) {
    const state = new FetchState(request);

    // APIリクエストをバックエンドサービスに転送
    if (state.url.pathname.startsWith('/api')) {
      const url = new URL(
        state.url.pathname + state.url.search,
        'https://backend-api.example.com'
      );
      return fetch(new Request(url, request));
    }

    // それ以外はAstroのページやエンドポイントにフォールバック
    return astro(state);
  }
}

Honoとの統合

アドバンストルーティングAPIはHonoとも互換性がある。Honoは軽量なWebフレームワークで、豊富なミドルウェアエコシステムを持つ。以下のようにBasic認証をAstroアプリケーションに組み込める。

import { astro } from 'astro/hono';
import { Hono } from 'hono';
import { basicAuth } from 'hono/basic-auth';

const app = new Hono();
app.use(basicAuth({ username: 'admin', password: 'secret' }));
app.use(astro());

export default app;
従来のミドルウェア(Before)
i18n Actions ミドルウェア ページ
認証チェックがActionsの後になるため、未認証のアクション呼び出しが発生しうる。レスポンスタイミングのログ出力も個別にラップする必要があった
アドバンストルーティング(After)
i18n 認証 Actions ミドルウェア タイミングログ ページ
認証がActionsより先に実行され、タイミングログはページレンダリングのみをラップする。コードを必要な場所に正確に配置可能

より高度な使い方として、個別のAstro機能を別々のミドルウェアとして構成できる。認証、Actions、ミドルウェア、i18n、ページの各レイヤーを任意の順序で積み重ねられるため、認証チェックをActionsより手前に置くといった制御がシンプルに実現できる。このsrc/fetch.tsファイルを追加しなければ、Astroの動作は従来通りだ。

ルートキャッシングとCDNプロバイダ連携

ルートキャッシングとCDNプロバイダ連携

オンデマンドレンダリング応答のキャッシュ制御は、ホスティングサービスごとに異なる仕組みで実装されてきた。Astro 7.0で安定版となったルートキャッシングは、デプロイ先を問わない単一のキャッシングAPIを提供する。

設定の流れはシンプルだ。まずキャッシュプロバイダを一度設定し、あとはページ内でAstro.cache(APIルートではcontext.cache)を使ってレスポンスごとにキャッシュ制御を記述する。標準的なHTTPキャッシングセマンティクスに従うため、特別な知識は不要だ。

import { defineConfig, memoryCache } from 'astro/config';

export default defineConfig({
  cache: {
    provider: memoryCache(),
  },
});
---
Astro.cache.set({
  maxAge: 120,          // 2分間キャッシュ
  swr: 60,              // 再検証中は1分間 stale を返す
  tags: ['products'],   // タグベースの無効化用
});
---

routeRulesを使えば、ルートグループ単位で宣言的にキャッシュルールを設定できる。

export default defineConfig({
  cache: { provider: memoryCache() },
  routeRules: {
    '/blog/[...path]': { maxAge: 300, swr: 60 },
  },
});

キャッシュの無効化はcache.invalidate()でタグ単位またはパス単位で行える。CMSのwebhookエンドポイントをAstroで実装し、コンテンツ更新時に該当キャッシュを破棄するといった使い方が可能だ。

CDNキャッシュプロバイダ

Astro 7.0では、Netlify、Vercel、Cloudflare向けのCDNキャッシュプロバイダが実験的機能として追加された(Cloudflareはプライベートベータ)。これらはレスポンスをメモリではなく、各プラットフォームのエッジネットワークにキャッシュする。キャッシュヒット時はサーバー関数を呼び出さず、CDNから直接応答が返るため、さらに高速なレスポンスを実現できる。

アダプタごとに/cacheエントリポイントからプロバイダをインポートする。

import { defineConfig } from 'astro/config';
import netlify from '@astrojs/netlify';
import { cacheNetlify } from '@astrojs/netlify/cache';

export default defineConfig({
  adapter: netlify(),
  cache: {
    provider: cacheNetlify(),
  },
});

Astro.cacherouteRulescache.invalidate()のAPIは、どのプロバイダでも同じように動作する。各プロバイダが、Astroのキャッシュディレクティブを各プラットフォームのネイティブなキャッシュ制御ヘッダと無効化APIに変換する仕組みだ。

AIエージェント向け開発サーバー機能

AIエージェント向け開発サーバー機能

AIコーディングエージェントの普及に伴い、Astro 7.0はエージェント駆動開発を支援する機能を導入した。AIエージェントは、終了しない長時間実行プロセス(開発サーバー)の扱いが苦手だ。シェルコマンドを実行し、終了を待って出力を読むワークフローに、開発サーバーは適合しない。

バックグラウンド開発サーバー

astro dev --backgroundコマンドを使うと、開発サーバーを管理されたバックグラウンドプロセスとして起動できる。コマンドはサーバーがリクエストを受け付け可能になるまでブロックし、URLとプロセスIDを出力してからデタッチする。ポーリングやスリープ、端末出力の解析は一切不要だ。

AstroはAIエージェント内で実行されていることを自動検出し、バックグラウンドモードを自動的に有効にする。エージェントワークフローでは--backgroundフラグの指定すら不要だ。

ロックファイルによって重複インスタンスが防止される。エージェントが誤って2つ目のサーバーを起動しようとすると、既存インスタンスの詳細が返される。astro dev statusで状態確認、astro dev stopで停止、astro dev logsでバックグラウンドサーバーのログを確認できる。また、全実行中の開発サーバーは/_astro/statusヘルスエンドポイントを公開し、エージェントがサーバーの生存を確認できる。

JSONログ出力

Astroのロガーが完全に設定可能になった。AIエージェント向けには、バックグラウンドモードの自動検出時にJSONログが自動的に有効化される。それ以外の用途でも、CLIまたは設定ファイルで有効化できる。

astro dev --json
import { defineConfig, logHandlers } from "astro/config";

export default defineConfig({
  logger: logHandlers.json()
})

構造化ログが必要なユースケースはAIだけではない。SSRで本番運用しているチームは、Kibana、CloudWatch、Grafana/Lokiといったログ集約サービスと統合するために構造化ログを必要としている。従来のAstroのログ出力は、色付き表示や罫線文字、複数行エラーフォーマットなど、人間の可読性に特化しており、機械による解析が困難だった。

compose() APIを使えば、人間向けのコンソール出力と機械向けのJSONログを同時に出力できる。

import { defineConfig, logHandlers } from "astro/config";

export default defineConfig({
  logger: logHandlers.compose(
    logHandlers.console(),
    logHandlers.json()
  )
})

この記事のポイント

  • Astro 7.0は.astroコンパイラとMarkdown/MDX処理をRust化し、ビルド時間を15〜61%短縮した
  • Vite 8のRust製バンドラRolldownが標準搭載され、既存の設定をほぼそのまま使える
  • アドバンストルーティングでリクエストパイプラインを完全制御でき、Honoとの統合も可能
  • ルートキャッシングが安定版となり、Netlify/Vercel/CloudflareのCDNキャッシュプロバイダも追加された
  • AIエージェント向けにバックグラウンド開発サーバーとJSONログ出力が自動有効化される
海田 洋祐

・ 複数業界における17年間のデジタルビジネス開発経験 ・ ウェブサイト開発のためのHTML、PHP、CSS、JavaScript等の実用的知識 ・ 15ヶ国語対応の多言語SaaSの開発経験 ・ 17年間にも及ぶ、Eコマース長期運営経験 ・ 幅広い業界でのSEO最適化の豊富な経験

メッセージを残す