定期的にやるやつ!
背景・モチベーション
(※個人的な話なので興味ない人は飛ばそう)
いろいろ使いたい
個人的な思想として、個人でやっているWebサイトはそれぞれ違う技術を使いたいというモチベーションがあります。
どうしてもお仕事だと長期的な保守のことやチーム開発のことを考えると、あまり尖った道具を採用することはありません。正直、よほど強い理由がない限りは React 系一択になる。
そのため、個人でやってるプロダクトでは、あまりお仕事で使ってないやつを試してみたい!というモチベーションがあり、特定の何かだけを使うのではなく、サイトごとに全部違うものを使ってみたいと思っています。
あと、僕個人のマインドとしてはテンプレート系が好きだったりはします。テンプレートが好きというかHTMLとCSSが好き。
そのため、現在も僕が保守している3つのサイトは以下のような技術構成になっていました。
- 鳥小屋ポータRu
- 僕の個人サークルのWebサイト
- Sveltekit
- 鳥小屋プラグイン置き場
- RPGツクール用のプラグインの公開サイト
- Astro.js
- プレポタ
- ブラウザゲームの遊べるサイト
- Sveltekit
……あれ、Sveltekit が2つになっちゃってるじゃん!!!111 ←モチベーション
それぞれのサイトに適したものを考える
以前の記事にもちらっと書いていましたが、『3. プレポタ』のサイトを作る際、最初は HonoX を使おうと考えていました。が、サイトの性質上、SinglePageApplicationのページであったほうが都合が良いという理由があり、おそらくプレポタの要件にあっているのは Sveltekit だろうと考え Sveltekit を採用しています。
『1. 鳥小屋ポータRu』のサイトは動的な要素はそんなに多くないため、正直 Sveltekit はオーバースペックです。別に Sveltekit である必要はない気がします。
そこで、それぞれのサイトに求められる要件をまとめ、採用技術の整理をすることを考えました。
- 鳥小屋ポータRu(個人サークルのページ)
- =作ったゲームたちの公式サイトの集合体
- 各ゲームごとにページのデザインは違う場合がある
- ゲームの雰囲気にあわせてページの構成が変わったりする
- 画像が多いのでちゃんと最適化とか必要
- → 画像最適化などの公式サポートがある Astro がよさそう
- 鳥小屋プラグイン置き場(RPGツクールのプラグイン公開サイト)
- すべてのページがデザイン固定
- コンテンツはすべて Markdown で書いている
- ページ数も少なめ。画像とかも少ない。
- → ぶっちゃけなんでも良さそう!
- プレポタ(ブラウザゲームのサイト)
- ログイン・ゲームのスコアランキングなどの動的要素があり、ステート管理やJavaScriptの処理が多い
- SinglePageApplication 的な要求が多い
- → 引き続き Sveltekit を使うのが良さそう!
- ログイン・ゲームのスコアランキングなどの動的要素があり、ステート管理やJavaScriptの処理が多い
というわけで、『1. 鳥小屋ポータRu』については Sveltekit ではなく Astro に置き換えることにしました。Astro は既に『2. 鳥小屋プラグイン置き場』で使ってしまっていますが、こちらのサイトは別に Astro である必要もそこまでないので、別の機会に何か面白そうなものに置き換えることにします。
本題:Sveltekit → Astro の置き換え
置き換え、といいつつ、Astro の中ではコンポーネントとして Svelte を利用することができます。そのため、元のサイトで使用していた一部のコンポーネントは概ねそのまま持っていくことができました。
……が、Astro の特徴の1つとして Astroアイランド があります。
Astro は基本的には静的サイトとしてビルドすると、ページ内から JavaScript が消え去ります。JavaScript で動く動的な要素を利用したい場合は、その部分だけをアイランドとして作成する必要があります。
特に問題ないでしょ~と思ったのですが、実際に移植している中で以下のような問題がありました。
.astro のコンポーネント以外から .astro のコンポーネントは呼べない
それはそう。
例えば、 Svelte のコンポーネントの中で以下のようなことはできません。
<script> import MyAstroComponent from './MyAstroComponent.astro'; // ←だめ </script> <MyAstroComponent />
例えば、サイトのロゴとかアイコンのような 共通部品を .astro のコンポーネントで作っていると、 Svelte などの他のフレームワークの中からは参照できなくなってしまいます。
これを避けるためには『基本的に全部 Svelte など他のフレームワークを使う』または『呼び出し元から slot / children として渡す』必要があります。
--- // 呼び出し元で、Astro のコンポーネントを import し、 slot / children で渡す import MySvelteComponent from './MySvelteComponent.svelte'; import MyAstroComponent from './MyAstroComponent .astro'; --- <MySvelteComponent> <MyAstroComponent /> </MySvelteComponent>
何もかも Svelte で実装するのもどうなんだ?という点と、 astro:assets
の提供する画像最適化を行う <Image>
コンポーネントを使いたかったので、僕は呼び出し元から渡す方法で実装を行いました。
が、一部で次の問題にぶち当たります。
Astroアイランドを使うと <astro-island>
という要素が生成される
例えば以下のような Astro ファイルを作成します。
--- import MySvelteComponent from './MySvelteComponent.svelte'; --- <div class="hoge"> <p>こんにちは</p> <MySvelteComponent /> </div>
するとレンダリング後のHTMLは以下のようになります。
<div class="hoge"> <p>こんにちは</p> <astro-island uid="xxxx" ....> <!-- ここに MySvelteComponent の中身 --> </astro-island> </div>
<astro-island>
という要素が作成され、その中にコンポーネントは描画されます。ハイドレーションするための情報がここに渡されているためです。
が、これによってHTMLの構造が変わることが非常に困った。
具体的に何に困ったのかというと『カルーセル』です。
ゲームの紹介ページなので、スクリーンショットを載せるようにカルーセルを多用していました。カルーセルの中には当然画像が入るため、画像については astro:assets
の <Image>
コンポーネントを使いたく、先ほどの呼び出し元から .astro のコンポーネントを渡したくなります。
// イメージ <CarouselComponent> <div class="item"><Image src={image01} /></div> <div class="item"><Image src={image02} /></div> <div class="item"><Image src={image03} /></div> </CarouselComponent>
が、カルーセルのUIライブラリは結構HTMLの構造に依存するものが多く、間によくわからないHTMLが挟まると動かない場合がありました><;
ひとまず今回いろいろ試したところ Embla Carousel は class 名などがなくても動かすことができたため、画像のカルーセルについては Embla Carousel を使う形で乗り切りました。
今思えば、画像だけのカルーセルの場合は、 Astro の getImage
関数で事前に最適化した画像のURLを作成して、その値を Svelte のコンポーネントに渡して Svelte の世界だけで完結させるという方法でも良かったかもしれません。
言い訳をすると、元のサイトには画像だけじゃないHTML要素もいろいろあるカルーセルもあり、こういった方法を取っていました。が、そっちは別のCSS的な問題でカルーセル周りが思うように動かない問題があり、最終的に画像以外のカルーセルは無くすという対応をしました><
おまけ:グローバルスタイルどこに置くの問題
Astro 、グローバルのCSSをどこに置いたらいいんでしょうね……
公式的には Layout の先頭で import しようね、という感じなのでしょうが、エントリーポイントでの import の順番で CSS 読み込まれる順番が変わる可能性があるの、ちょっとやな感じがします。
とりあえず今回は「先頭で読まなきゃだめだよ!」みたいなコメント書いて未来の僕に託しましたが、いつか壊しそ~。
@layer
の優先度設定するやつだけは何よりも先頭に読みこませたいので、本当はグローバルに必ず一番最初に読み込まれるCSSを設定したいなぁ。どうやるのがいいんだろうなぁ。
できた!
ページ数がまぁまぁあるので少し時間はかかりましたが、全ページきっちり移植完了しました。
Astro はビルド時にJavaScriptを消してくれたり画像の最適化もしてくれたりするので、なんとなく体感も早くなった気がします。試しに PageSpeed Insights してみたところ、モバイルでもパフォーマンス100点出せる場合があり、ほえーという気持ちに。
でもTOPページに動画流れるページのパフォーマンスが100点なわけないでしょ
また、今回の Astro 化によってサイト自体がSPAからMPAに戻ったわけですが、このサイトはページごとにデザイン(というか配色)が違う場合もあり、SPA遷移してもキレイではなかったので、そういった意味でもMPAのほうが向いてるサイトだったかもしれませんね。
さて、次は Astro が2つになっちゃったので、『2. 鳥小屋プラグイン置き場』を別のなにかに置き換える旅ですね!こっちはページ自体シンプルだし、以前試してやめちゃった HonoX でもいいし、なんか全然違うもの使ってみても良さそう。なんか面白そうなのあるかなー?