当技術ブログをAstroに移行しました。

2023/03/23に公開されました。
2023/03/23に更新されました。

当技術ブログをAstroに移行しました。


author: komem3

背景

当ブログは最近までNuxt 2のStatic Site Generation(SSG)機能を使用して作成されていました。 しかし、Nuxt 2はNuxt 3の開発が始まった途端メンテナンスが止まっており、セキュリティ的な問題はないにしても困り果てていました。 Nuxt 3への移行もマイグレーションガイドが存在するも、全然移行が上手くいかず(今は上手くいくかも?)、いっそのこと違うフレームワークを使用しようとなったのが今回の背景になっています。

静的サイトを生成するための選択肢

選択肢は大量にあります。今回選択肢として上がってきたのは以下のようなフレームワークです。

これらは静的なサイトを生成しますが、コンセプトや挙動はそれぞれ異なります。大きく分けるとして、Astroのドキュメント風に書けば以下のようになります。

MPAはいわゆる、ページ毎にサーバにリクエストをかけて、都度取得したjsやHTMLを使用する方式になっています。そのため単純な生成システムで生成速度がとても速いです。
対してSPA最初のリクエスト移行はReactやVueのルーティングを使用してSingle Page Application(SPA)の挙動になるため、生成は遅いですが最初のリクエスト移行のページ遷移がとても速いです。

どちらの方法も一長一短ある方法です。この辺の話は Astro のドキュメントに書いてあるので今回は掘り下げませんが、とても興味深い話です。

Astroの選定理由

今回の移行背景から、なるべく大きなフレームワークを使うのは避けたいという気持ちがありました。ブログサイトにSPA系のフレームワークはオーバースペックという考えもありました。 そのため、MPA系が選択肢に上がります。Vueのコードを移行することを考えたさいReactかVueを自然に使えるフレームワークを選択したいとなり、それらを満たすAstroを選びました。

大分消去方な理由でありAstroの技術的なよさに後で気付きましたが、最初のモチベーションとしてはそんな感じでした。

移行作業

単純な移行作業

まずはロジックをもたない単純なHeaderやFooterから移行し、見かけの確認をしながら移行していきました。ここでAstroの使い勝手や癖を掴みたかった感じです。 Astroの良い所として、 .astro ファイルにHTMLやJSXを殆ど書かずに、ReactやVueで書いた .ts ファイルをimportして組み合わせられる所があります。 この利点のおかげでこの単純な移行作業はとても早く終わりました。(HeaderとFooterだけなら1時間かからないぐらいで終わりました) また、当ブログはUIフレームワークにtailwindcssを使用していたため、UIフレームワークによる嵌りは殆どありませんでした。

content API → Astro.glob

Markdownの取得及びHTML変換はNuxt 2の時はcontent APIを使用していましたが、 Astroに移行するさいはAstro.globによって同様のことを行ないました。全件取得するだけなら Astro.glob の方が使いやすく、個人的に良いAPIでした。 しかし、 Astro.glob.astro ファイルでしか使用できないため、強力なAPIですがループとか回すときに補完が効かなかったのでその辺不便でした。( astro check で型チェックはできるみたいですが…) そのため、受け取った値は積極的にimportしたcomponentに投げて他のフレームワークの型恩恵を利用して開発しました。

content APIのような細かい絞り込み(where)はできないので、その辺は自前で行なう必要があります。しかし、静的サイトにおいてそんなAPI提供されていてもオーバースペックなので、ただ取ってくるだけの Astro.glob は良さげでした。

また、ここがAstroの良かった点ですが、markdownファイルからのルーティング生成が個人的にとても好みでした。 AstroではgetStaticPathという関数にparamを登録することで動的なルーティングを登録します。 この getStaticPath がHTMLを書くファイルと同じ所にあるため、ロジックが固まっており生成するPathも色々と融通が効くのがとても良かったです。当ブログでは以下のような関数が登録されています。

export async function getStaticPaths() {
  const articles = await Astro.glob<Frontmatter>("../../../articles/*.md");

  return sortArticles(articles).map((article, index, array) => ({
    params: {
      slug: slug(article.file),
    },
    props: {
      prev: array[index + 1],
      next: array[index - 1],
      article,
    },
  }));
}

interface Props {
  prev: MarkdownInstance<Frontmatter>;
  next: MarkdownInstance<Frontmatter>;
  article: MarkdownInstance<Frontmatter>;
}

const content = Astro.props;

単純で分かりやすいコードですね。

ダウンロードするサイズを小さくする

Astroを使っていると、極力ReactやVueのruntimeをダウンロードさせないようなサイトを作成したくなります。 ユーザに余計なものをダウンロードさせないというAstroの哲学を叶えるための今回した工夫は幾つかあります。

誰でも見られるHeaderです。これは携帯の場合ハンバーガーメニューがあるため状態管理でメニューの出しわけをしていました。 脱jsしたいですね。 そのため、今回はcheckboxと一般兄弟結合子を使用して元の挙動に最大限近くしました。一般兄弟結合子、今回初めて知りましたがすごいですね😳。

TOC

こちらは元々Vueの良く分からないライブラリを使用していました。今回は全体的にReactで書いていたため、Intersection APIを使用して自前で実装することにしました。 しかし、記事ページが最も見られるページなのにそのページだけReactのruntimeをダウンロードするのは勿体ない気がしました。(Astroのデフォルトの挙動は、HTMlの生成のみにReactを使用するだけで、それ移行は指定しな限りランタイムをダウンロードしません) そのため、TOCのコードはTypescriptで記載し、それをimportすることで、生jsとして読み込むようにしました。

<script>
  import { addEvent } from "../../components/tocEvent";
  addEvent();
</script>

ビルド時に上記のコードをいい感じに変換してくれています。

終わりに

こんな感じに、ちょこちょこ移行作業をすることでこっそり移行作業は完了しました。 サイト自体が小さいのもありましたが、Astroがとてもいいフレームワークだったのが大きいと個人的には思っています。 いい技術は適所があれば積極的に採用していきたいですね。




GI Cloudは事業の拡大に向けて一緒に夢を追う仲間を募集しています

当社は「クラウドで日本のIT業界を変革し、世の中をもっとハッピーに」をミッションに掲げ、Google Cloudに特化した技術者集団として、お客様にコンサルティングからシステム開発、運用・保守まで一気通貫でサービスを提供しています。

まだ小規模な事業体ですが、スタートアップならではの活気と成長性に加えて、大手総合商社である伊藤忠グループの一員としてやりがいのある案件にもどんどんチャレンジできる環境が整っています。成長意欲の高い仲間と共にスキルを磨きながら、クラウドの力で世の中をもっとハッピーにしたい。そんな我々の想いに共感できる方のエントリーをお待ちしています。

採用ページ

※本記事は、ジーアイクラウド株式会社の見解を述べたものであり、必要な調査・検討は行っているものの必ずしもその正確性や真実性を保証するものではありません。

※リンクを利用する際には、必ず出典がGIC dryaki-blogであることを明記してください。
リンクの利用によりトラブルが発生した場合、リンクを設置した方ご自身の責任で対応してください。
ジーアイクラウド株式会社はユーザーによるリンクの利用につき、如何なる責任を負うものではありません。