見出し画像

Astroを使った、非Web開発者でもWebサイトを更新しやすくする仕組み作り

こんにちは、ちょくにゃんです。

ナビタイムジャパンで、法人向け店舗データ管理・発信クラウドサービス『NAVITIME Location Cloud』の開発・運用を担当しています。

今回は、静的なWebサイトのリニューアルにおいてAstroフレームワークを導入し、普段Webフロントエンド開発を行わない人・プロジェクトでもコンテンツの更新ができるような仕組み作りについて紹介したいと思います。

静的Webページの更新に、課題を感じているプロジェクトでの工数削減や課題解決のきっかけになれば幸いです。


背景

サービス紹介サイトのリニューアルを任される

私は昨年度、歩数計アプリ『ALKOO by NAVITIME』の開発をしているプロジェクトに、ヘルプという形で一時的に異動しました。

そのプロジェクトにはWebフロントエンド開発をメインで行っているエンジニアがおらず『ALKOO』の法人向けサービスである『ALKOO for Business』の紹介サイトの更新ができていないという課題がありました。

今回その紹介サイトのリニューアルを行うことになり、普段Web開発を行っているエンジニアとしてその開発を任されました。

更新しやすいサイトにしたい

法人向けサービスの紹介サイトでは、サービス自体の説明はもちろんですが、どういった企業や自治体が導入しているのか、どのように活用しているのかという情報もマーケティング上重要になります。
しかし、紹介サイトの更新をできる人がいないために、多くの企業・自治体に新たに導入いただいていたにもかかわらず、その事例を紹介できていませんでした。

更新がしにくい理由として、サイトがHTMLをそのまま公開する形式になっていることがありました。
各ページ共通のヘッダーやフッターはソースコード上では共通化されておらず、スタイル指定のためのたくさんのクラスが付与されている状態で、導入事例の掲載を増やそうにもどこまでをコピーして編集すればきちんとしたHTMLになるか、Web開発者以外が考えて更新するのは難しい状態になっていました。

例えば、元々の各ページ下部にあった導入事例を表示するパーツは、次のようなHTMLで書かれていました。

<section class="case" id="case">
  <h5>導入事例</h5>
  <div class="container">
    <ul class="no-photo">
      <li class="no-photo__item">
        <a href="XXX.html" target="_blank">
          <p>グループ全体の健康経営施策の一環として「ALKOO for Business」を導入</p>
          <span class="instance">XXX株式会社</span>
        </a>
      </li>
      <li class="no-photo__item">
        <a href="YYY.html" target="_blank">
          <p>健康経営施策の第一歩として「ALKOO for Business」を導入</p>
          <span class="instance">YYY株式会社</span>
        </a>
      </li>
    </ul>
  </div>
  <div class="swiper-container" id="sp-slide">
    <div class="swiper-wrapper">
      <div class="swiper-slide">
        <div class="swiper-slide--item no-sp">
          <a href="XXX.html" target="_blank">
            <p>グループ全体の健康経営施策の一環として「ALKOO for Business」を導入</p>
            <span class="instance">XXX株式会社</span>
          </a>
        </div>
      </div>
      <div class="swiper-slide">
        <div class="swiper-slide--item no-sp">
          <a href="YYY.html" target="_blank">
            <p>健康経営施策の第一歩として「ALKOO for Business」を導入</p>
            <span class="instance">YYY株式会社</span>
          </a>
        </div>
      </div>
    </div>
    <div class="swiper-pagination"></div>
  </div>
</section>

PC用とスマホ用の表示を分けるために同じ内容が2セット書かれており、さらにこれが各ページ用のHTMLにそれぞれ配置されていました。
この状態から掲載する導入事例を1つ増やそうとしたときに、必要なタグやクラス指定が抜けたりサイト内のあるページだけ更新されていないということが起きやすい状態でした。

今回サイトの内容のリニューアルを行うにあたって、同時に非Web開発者でもサイトの更新がしやすいこと開発者体験の向上を両方満たせるような技術構成にしたいと考えました。
複数のページで繰り返し使うパーツはコンポーネントとして管理し、内容の更新についてはHTMLやCSSを意識せずに更新できるようにするイメージです。

技術選定の結果Astroを選択

このような背景を踏まえて技術選定を行った結果選んだのが、Astroというフレームワークです。

Astroは2021年に登場し2022年8月に正式リリースされた比較的新しいフレームワークで、コンポーネントなどのモダンな手法を使って開発しつつ、表示が高速な静的サイトを作ることができます。

次のような特徴が今回の要件に合っていると思い、Astroを選択しました。

1. コンポーネント管理ができる

Astroは標準でAstroコンポーネントという仕組みを持っており、ページの中に別のコンポーネントを配置することができます。もちろん親側からコンポーネントへデータを受け渡すこともでき、よくあるコンポーネント開発と同じことができます。

また、AstroはReact、Vue、Svelteといった他のフレームワークのコンポーネントをそのまま組み込むことができます。今回の開発では使いませんでしたが、他のフレームワークからの移行も他のフレームワークへの移行もしやすい状態で開発することができます。

2. 完全静的化される

SPA(Single-Page Application)フレームワークを用いてページを作った場合、ページ表示後の画面の切り替えが早くなりリッチなUIを作りやすい利点がありますが、初回読み込み時にフレームワーク自体の読み込みとページ内容の取得・生成が必要なため、初期表示が遅くなりやすくなります。

一方のAstroはMPA(Multi-Page Application)フレームワークで、ページごとに個別のHTMLファイルが作成されます。
また、JavaScriptによるページ内容の取得や生成は全てビルド時に行われ、JavaScriptが全て排除された軽量なHTMLを出力してくれるのが特徴です。

その場での通信結果によって表示内容が次々に変わるようなWebアプリケーションであればSPAのほうが向いていますが、内容が頻繁には変わらずビルド時に取得できれば問題ないようなページであれば、Astroのような完全静的化できるフレームワークのほうが向いています。

3. 更新が活発で社内利用も増えてきた

Astroは新しいフレームワークですが、2023年1月にはバージョン2が、2023年8月にはバージョン3が公開されるなど、機能追加や改善が活発です。

ナビタイムジャパン社内でもAstroを利用するプロジェクトが出てきており、技術的な利点以外の部分も導入の後押しになりました。

CMSを使わなかった理由

Web開発者以外でも更新できるように、という目的を考えると、WordPressやMovable TypeといったCMSを使う選択肢も考えられます。しかし今回は、CMSを使うほど更新頻度が高いわけでも記事のような長い文章で構成されるコンテンツを更新するわけでもなかったため、CMSではオーバースペックでした。むしろCMSではデザインの自由度が下がってしまうため、デザイン仕様通りに作りやすい環境を重視して選びました。

近年人気のヘッドレスCMSという選択肢についても同様で、コンテンツを別で管理するほど高度なシステムは不要なサイトだったので、Astroが持つコンテンツ管理の仕組みを利用することにしました。

コンテンツを更新しやすくする仕組み

ここからは、コンテンツを更新しやすくする仕組みをAstroを使ってどのように実現したかを紹介していきます。

表示したいデータと表示のさせ方を分けて管理する

Astroコンポーネント(*.astro)は、スクリプト(JavaScript)とテンプレート(HTML)から構成されます。このスクリプト部分に画面に表示したいデータを含めることで、ビルド時にはスクリプトが排除された状態でHTMLが生成されるという仕組みです。

今回のように非Web開発者でも更新しやすくしたい場合、Astroコンポーネントのような特殊なファイルを編集してもらうのは現実的ではありません。そこで、更新が必要なデータはJSONファイルとして切り出し、それをAstroコンポーネント内で読み込むような形にしました

例えば導入事例について、次のようにJSONファイルを作成しておきます。

[
  {
    "organization": "XXX株式会社",
    "description": "グループ全体の健康経営施策の一環として「ALKOO for Business」を導入",
    "imageUrl": "https://www.navitime.co.jp/healthcare/XXX.jpg",
    "link": "https://www.navitime.co.jp/healthcare/XXX.html"
  },
  {
    "organization": "YYY株式会社",
    "description": "健康経営施策の第一歩として「ALKOO for Business」を導入",
    "imageUrl": "https://www.navitime.co.jp/healthcare/YYY.jpg",
    "link": "https://www.navitime.co.jp/healthcare/YYY.html"
  },
  ...
]

JSON形式のファイルであればWeb開発者でなくても使用する機会が多く、また複雑な環境構築もせずに編集ができます。

あとはこのデータを読み込んでHTMLを生成できるようなAstroコンポーネントを作成します。

---
import case from '@/data/case.json'; 
---

<ul class="case">
  {
    case
      .slice(0, 5)
      .map((item) => (
        <li class="item">
          <img src={item.imageUrl} />
          <div class="content">
            <div class="organization">{item.organization}</div>
            <div class="description">{item.description}</div>
            <a href={item.link}>詳細を見る</a>
          </div>
        </li>
      ))
  }
</ul>

ここではJSONファイルから読み込んだデータの最初の5件を表示するようなテンプレートを書いてみました。これをビルドすると、データが埋め込まれたli要素が5個並ぶだけのシンプルなHTMLが生成されます(実際には各HTML要素に識別用の属性が付与されますが、JavaScriptは含まれません)。

<ul class="case">
  <li class="item">
    <img src="https://www.navitime.co.jp/healthcare/XXX.jpg" />
    <div class="content">
      <div class="organization">XXX株式会社</div>
      <div class="description">グループ全体の健康経営施策の一環として「ALKOO for Business」を導入</div>
      <a href="https://www.navitime.co.jp/healthcare/XXX.html">詳細を見る</a>
    </div>
  </li>
  <li class="item">
    <img src="https://www.navitime.co.jp/healthcare/YYY.jpg" />
    <div class="content">
      <div class="organization">YYY株式会社</div>
      <div class="description">健康経営施策の第一歩として「ALKOO for Business」を導入</div>
      <a href="https://www.navitime.co.jp/healthcare/YYY.html">詳細を見る</a>
    </div>
  </li>
  ...
</ul>

このように、表示したいデータはJSONファイルという簡単な形式で、表示の仕方やデータの絞り込みはAstroコンポーネントで、と棲み分けをすることができ、表示の仕方さえ変わらなければ表示する内容の更新はJSONファイルを編集するだけ、という簡単な作業にすることができます。

サイトの更新はビルドを実行するだけ

Astro自体はNode.jsで実行されるため、ビルドはnpmコマンドで行います。このあたりはJenkinsなどで自動化しておけば、開発者でなくても本番環境へのリリースを行うことができます。

もしJSONの構文等に問題があった場合はビルドが失敗し本番環境へ反映されないだけなので、ミスによってサイトが落ちてしまう心配もありません。

開発効率や成果物の質がアップ

今回のサイトリニューアルでは非Web開発者でも内容の更新ができるような仕組み作りを重視しましたが、Astroを導入したことで同時に開発効率や成果物の質についても向上させることができました。

パーツの共通化で開発効率アップ

Astroでは、ページのレイアウト、各ページ、ページ内のパーツなどは全てAstroコンポーネントという共通の形で定義し、それらを自由に入れ子にすることができます。それにより複数のページで同じパーツを使い回しやすくなったり、ページごとに異なる変数を持たせて値を埋め込んだりすることができます。

例えば、Layout.astroというファイルを次のように作成し、

---
export interface Props {
  title: string;
  description: string;
}

const { title, description } = Astro.props;
---

<!DOCTYPE html>
<html>
  <head>
    ...
    <title>{title}</title>
    <meta name="description" content={description}>
    <meta property="og:title" content={title}>
    <meta property="og:description" content={description}>
    ...
  </head>
  <body>
    <slot />
  </body>
</html>

各ページのファイルを次のような形で作っておけば、

---
import Layout from './Layout.astro';
---

<Layout title="ALKOO for Business トップページ" description="ナビタイムの健康経営支援パッケージです。">
  <div class="wrapper">
    <h1>トップページ</h1>
  </div>
</Layout>

このページはビルド後には次のような形で出力されます。

<!DOCTYPE html>
<html>
  <head>
    ...
    <title>ALKOO for Business トップページ</title>
    <meta name="description" content="ナビタイムの健康経営支援パッケージです。">
    <meta property="og:title" content="ALKOO for Business トップページ">
    <meta property="og:description" content="ナビタイムの健康経営支援パッケージです。">
    ...
  </head>
  <body>
    <div class="wrapper">
      <h1>トップページ</h1>
    </div>
  </body>
</html>

このように、HTMLを直接編集する場合では変更箇所が複数に及ぶような内容でも、Astroコンポーネントのpropとして定義して共通化しておくことで、1箇所を書き換えればページやサイト全体で書き換えられるようになります。Astroというよりはコンポーネント開発に共通する利点ではありますが、開発者としても効率よく開発することができるようになりました。

SEOにも良い影響

上で触れたように1箇所のデータ定義でサイト内の複数箇所への反映ができるため、リンク共有時やSEOで重要になるOGPタグやパンくずリストの構造化データなどが作りやすくなります。それでいて完全静的化された状態でサイトを公開できるため、ページのパフォーマンスもSPAフレームワークを用いる場合と比べて向上します。

最初に整備さえしておけばページ内容の更新時にSEOを意識したコーディングが不要になるため、SEOの観点でも開発者にも更新者にも優しいサイトにすることができます。

今回のサイトリニューアルで、特にパフォーマンスとSEOの観点でLighthouse(Webページの品質を数値化してくれるGoogle製ツール)のスコアを向上させることができました。リニューアル前と比べて全指標合わせて26向上しています。

サイトリニューアルで上昇したLighthouseスコア
全ての指標が90点台後半〜100点になった

更新のハードルを下げることができた

今回リニューアルしたサイトがこちらです。

リニューアルによって、導入事例だけでなく導入企業のロゴやよくある質問の更新もJSONファイルの編集だけで可能になりました。

リニューアル後のサイトは簡単に更新できる箇所が増えた

実際にサイトの更新を行う方に話を聞いたところ、従来はHTMLのコピペによる更新で既存への影響が怖かったが、JSONだけで更新できるようになりとても楽になった、更新にかかる時間は10分の1くらいになった、とのことでした。マーケティング強化という本来の目的により多くの時間を使えるようになったのではと思っています。

その他の使い道

ここまではサービス紹介サイトのリニューアルという実例ベースで紹介してきましたが、他にもAstroが向いている使い方を紹介します。

Markdownからお知らせページを作る

AstroはMarkdownファイルからのページ生成にも対応しています。レイアウトさえ用意しておけば、1つのMarkdownファイルに対し1ページを自動で生成してくれます。

例えば、スマホアプリ内のお知らせページがHTMLのWebView表示で実装されていたとします。その場合、各お知らせページの作成はアプリ開発者が行うこともあると思いますが、ここでAstroを使ってMarkdownファイルでお知らせを記述できるようにすれば、毎回不慣れなHTMLやCSSをコピペして作るようなことをせずに共通のデザインでページを増やしていけるようになります。

データから大量のページを生成する

サービス紹介サイトの例ではページ内の繰り返しコンテンツの表示にJSONファイル内の配列を用いましたが、配列の各要素から複数のページを生成することもできます。

例えばスポットの検索数ランキングのページを作ろうとした場合、元データとなるスポット情報とその検索数の配列を作っておけば、ランキングページだけでなく各スポットを紹介する個別ページも自動で作ることが可能です。

引き継ぎ後のことを考えた技術選定とドキュメント整備

最後に、Web開発者がいないプロジェクトにWebの仕組みを導入するWeb開発者側の話もしておきたいと思います。

技術選定

今回私はヘルプという形であらかじめ期間が決まっての異動でした。つまりヘルプ期間が終われば今回導入した仕組みの管理から手を離すことになります。そうなるといくら非Web開発者でも扱いやすい仕組みにしていたとしても、その仕組み自体を残されたメンバーが触らないといけない状況も訪れるはずです。

技術選定においては、非Web開発者が更新しやすい、Web開発者が開発しやすい、成果物の品質が高いことを理由にしていましたが、元々のメンバーが開発を行うことになった場合、下手にフレームワークを導入するとむしろ開発のハードルが上がってしまいます。

Astroに関しては環境構築が比較的簡単でHTMLが多少わかればページの修正ができないことはないので、今回は許容しました。また導入による利点と欠点を事前にPMに説明することで許可をもらいました。ただ、いくら便利だからといって新しい技術に飛びついてしまうと、それを引き継ぐメンバーが苦労してしまうことになりかねないので慎重な選択が必要だと思いました。

ドキュメント整備

今回は社内でまだ採用例が少ないAstroを利用したため、ドキュメントは厚めに整備しました。ページ内容の更新方法だけでなく、環境構築やそもそものAstro自体の仕組みの説明なども残しています。更新者向けと開発者向けで大きく分けて記述することで、その人にとって必要な作業がわかるようにしました。

更新者向けと開発者向けで分けて記述したドキュメント

アクセス解析も用意

サービス紹介サイトも1つのプロダクトであり継続的な改善が必要です。そこで、現状把握とその後の改善策の検討に必要になってくる、サイトのPVやUU、アクセス時の検索キーワードといった情報を簡単に確認できるようにしました。

実際にサイトの改修を行うとなるとやはりWebの技術は必要にはなってしまいますが、リニューアル前よりは改善サイクルを回しやすい状態にすることができたと思っています。

終わりに

Astroというフレームワークを導入し、Web開発者以外の人でも更新しやすくなる仕組み作りをしたことについてご紹介しました。導入にはどうしてもWeb開発者の力は必要になってしまいますが、Webアプリ開発以外の現場でも役に立つ技術かと思いますので、Webの現場に限らず活用できる場が無いかぜひ探してみてください。

最後までお読みいただきありがとうございました!