okayurisotto.net

私が好きでやったことが他の人のためにもなったらお得かも!

個人ブログをAstroからHugoへ移行した

公開日:
最終更新日:

はじめに

このブログ(okayurisotto.net)はこれまでAstroというWebフレームワークを使って開発されていました。当時の記事ではAstroについて次のように述べています。

その使い勝手は、「JSXライクに書けるようにしたHugo」、「Hugoのように手軽なNext.js」というようなものだと個人的には感じました。そしてそれが、私のニーズとうまく噛み合っているように感じられました。
Astro製ブログをCloudflare Pagesでデプロイした | okayurisotto.net

しかし実際にAstroでブログを開発してみて、いくつかの厄介な問題が発生したため、Hugoによって作り直しました。

Astroでのブログ開発の問題点

Astroでの開発の問題は主に次の2点に要約されます。

  1. 開発環境の複雑さによって手間のかかるデプロイ。
  2. Astroの独自記法の仕様の非直感的さ。

前者の問題についてはそもそもの静的サイトジェネレータとしての方針の違いもあるため仕方ない部分もあるかとは思いますが、デメリットであることは否めません。Hugoはシングルバイナリで一通りのことができる静的サイトジェネレータですが、AstroはNode.js上で動くフレームワークであり、その実行にはNode.jsnpmが必要です。

このブログはCloudflare Pagesでデプロイされているのですが、例えば以下のような面倒がありました。

  • Node.jsのバージョンを指定するためには.nvmrcが必要です(公式ドキュメント)。このファイルはnvm(Node Version Manager)のためのファイルです。しかしながら私はローカル開発ではこの用途にnvmではなくmise-en-placeを使っています。
  • 私はnpmの代わりにpnpmを使っています。このためにはpackage.jsonにてpackageManagerプロパティの値を適切に設定しておくことが必要です。これはCorepackというNode.jsに同梱されたパッケージマネージャーマネージャーを使って行う必要があります。しかしNode.js v25以降ではcorepackはNode.jsに同梱されなくなることが決定されています(公式ドキュメント)。「Stability: 1 - Experimental」が外れることなく、CorepackはNode.jsから削除されるのです。
  • そしてこれらの面倒を乗り越えた上で、Astroやそのサードパーティライブラリのバージョン管理や更新作業が待っています。AstroではRSSの生成に追加でライブラリをインストールする必要があり(公式ドキュメント)、またminifyにはサードパーティーのライブラリが必要です。

これらの面倒を乗り越えて初めて、Astroでの開発とデプロイが可能になります。どうしてもHugoに比べると複雑ですし、最近何かと話題になってしまっているnpm経由で配布されるInfostealerのサプライチェーン攻撃などを考えるとあまりいい気分にはなりません。

とはいえ前述したように、これはHugoに対してAstroが目指すものが異なるがゆえの特性です。AstroはWebフレームワークであって、Hugoのように既存のテーマをインストールして使うようなものでは基本的にありません。むしろNext.jsNuxtに近いものであると言えるでしょう。Astroは「MarkdownとテンプレートからHTMLを出力するシングルバイナリアプリケーション」とは異なります。

しかし同時に、Next.jsやNuxtとも異なります。Next.jsはJSX(.jsx)を、NuxtはVue SFC(.vue)を開発言語として使います。しかしAstroは.astroな独自言語を使い、Islandsアーキテクチャに基づいてReactやVueなどの複数のフロントエンドフレームワークが混在した開発を可能にするものです。

これはAstroの最も面白い部分であり、同時に最も戸惑う部分です。JSXやVue SFCのようでありながらもそれらとは異なる独自仕様の言語は、だいぶ戸惑う挙動をします。

例えばAstroでは、import "./style.css";のような、Viteでの開発で一般的な形でスタイルをインポートできます。また、Vue SFCでのように<style>タグを使ってスタイルを記述することも可能です。しかしそこで記述したスタイルはCSSファイルとして出力されることはなく、HTMLに<style>として展開される形になります。ですのでチュートリアル通りにセットアップしたAstroプロジェクトにおいて、/dist/ディレクトリ内にCSSファイルやそれを<link>によって参照するHTMLは1つも存在しません。

また、そのインラインスタイルのCSSセレクタは非直感的な形をしています。一般的なCSS Modulesであれば各要素に一意なclass名が自動生成・付与されることでスコープの分離が行われますが、Astroではclass名ではなく、data-astro-cid-*のようなdata属性によって行われるようです。よってHTMLに埋め込まれたCSSでは、p[data-astro-cid-abcdefgh]a[data-astro-cid-ijklmnop].activeといった記述をよく目にします。

一般的なWebフレームワークやWebフレームワークを使わないシンプルな開発におけるセオリー(Code Splittingや<link>による参照)をまったく使わないこの設計は、どうしても非直感的で、パフォーマンスの問題が発生しないか不安になるものです。ほとんどすべての要素に非常に長いdata属性が付けられ、CSSセレクタもまた一つ一つが長いのです。

Hugoへの移行

Hugoを選んだ決め手は次の3点です。

  • 開発環境がシンプルであること。
  • ついでにビルド速度も速いこと。
  • デファクトスタンダードであるがゆえにWeb検索をすれば大抵の問題が解決すること。

ただしHugoにも欠点はあります。

  • 仕様が難解であり、あるHTMLを出力する仮定でどのテンプレートがどう呼び出されているのか追うことが素人には不可能に近いこと。
  • 仕様の難解さと長い公式ドキュメントによって、どこに何が書いてあるのかわかりづらいこと。(実現したい内容をWeb検索することで逆引き的に参照するしかない。)
  • Go言語由来の日付フォーマット形式(2006年1月2日)が非英語圏のユーザー(≒日付を柔軟にフォーマットしたいと思う人)にとって著しく非直感的であること。

実際に移行を行うにあたり、Markdownのfrontmatterを編集する必要がある点には特に戸惑いました。Hugoではあらかじめ決められた語彙に基づいてfrontmatterを設定しておく必要があり、例えば私が個人的に使っていたpublishedAtupdatedAtといったメタデータをそれぞれdatelastmodに変更する必要に迫られました。エディタの一括置換機能により対応はできましたが、決め打ちの語彙に基づくというのは融通の効かない仕様であると言わざるを得ません。

また、完全に同じ形には移行できず妥協してしまった部分(タグ一覧ページでのソートや各タグのページのタイトル文字列の内容)などもあり、HugoのTemplatingの複雑怪奇さはなかなか大変です。

逆にスムーズに移行できたこととしては、RSSやsitemapの生成やminifyといった静的サイト開発において必須級の機能がすでにHugoには搭載されていたことでしょう。minifyすらサードパーティライブラリのインストールを必要とするAstroに対し、Hugoは“Hugoのやり方に従うのであれば”楽に開発できるということでしょう。

ビルド処理も、Hugoの場合はhugo --minifyコマンドを実行するだけで0.1秒とかからず完了するため楽でした。Cloudflare Pagesを使っているためコストの問題はもとからありませんでしたが。

おわりに

正直なところ作り替えるだけの価値あるブログではないと感じているため、移行なんてことはせず放置していてもよかったかもしれないとも感じています。今後このブログに何を書くかは未定です。