Blog
モダンWeb開発「JAMstack」を実践
GPを開発しました。
優れたWeb制作会社やデザイン会社の企業情報・実績のまとめサイト「good productions」を開発しました。
このサイトでは東京、大阪を中心に全国の制作会社とその実績をご紹介したり、Web制作におけるノウハウも記事として掲載しています。
ジャンルとしてはメディアサイトに位置付けられます。
開発概要
サイト機能
- 企業・実績の各種項目による検索
- キーワード検索
- お気に入り登録
- お気に入り共有
- CMSでのデータ・記事登録
メディアサイトで必要な各データを検索できたりお気に入り登録できるなど、基本的な機能を備えています。
使用技術
- Nuxt.js
- HeadlessCMS
- サーバーレス
- Github Actions(CI)
基本的に使用した技術構成は上記です。
HeadlessCMSとサーバーレスを使いJavaScriptのフレームワークで構築する、いわゆるJAMstack構成になります。
※JAMstackの説明は後述
Github Actionsでビルド、デプロイに加え、チャットへの通知なども行っています。
JAMstackに取り組んだ経緯
今回開発するにあたり、通常のサイトやWordpressなどのCMS以外を試すチャンスでもありました。
自社サービスの制作ではこの技術選定が醍醐味の一つだとは思いますが、機能はありつつも高速に動作し、OGPなども考慮しつつCMSで更新ができるサイトをと考えました。
SPA(シングルページアプリケーション)やSSR(サーバーサイドレンダリング)の構築などを試したり受託案件としても経験もあったので、今回はSSG(静的サイトジェネレート)を行い高速なサイトでかつ機能的にもSPAやSSRに劣らないJAMstack構成で開発することにしました。
JavascriptのフレームワークはVue.jsベースのNuxt.jsを選びました。
理由としては、開発の人数が複数人であり、自分の中でだけルールが固められていればいいという状況ではないため、Reactに比べると構造に一定のルールが設けられているVue.jsの方がロジックの共有を素早く集中して行えると考えたからです。
そのVue.jsと主要なVue.jsプラグインがまとまっているフレームワークがNuxt.jsです。
サーバーホスティングは費用を抑えつつ高速なレスポンスがしやすいサーバーレスを念頭に、コストを抑えつつ後のスケールもしやすいFirebaseを選択しました。
元々弊社はAWSをメインで使っていたりするのですが、Googleのサービスも利用していることから完全に無料で始めつつもGCP(Google Cloud Platform)への移行のしやすさというのも決め手になりました。
そしてCMSですが、Nuxt.jsとも相性がいいHeadlessCMSを選択しました。
HeadlessCMSを簡単に説明すると、フロント部分がなくAPIが作れるCMSという感じです。
このHeadlessCMSはたくさんのサービスやオープンソースなどが選択肢としてあります。
今回は記事数に制限がなく無料からスタートでき、また日本語のUIという部分でも国産サービスのmicroCMSを選択しました。
実際に開発することで見えてきた課題
冒頭で挙げている使用技術やJAMstackで開発を進めていくにあたり、単純に設計しただけでは想定できていなかったことや、やってみたからこそ掴めたそれぞれの特性や、メリットデメリットなどがありました。
そういったポイントを少しご紹介します。
JAMstackのポイント
JAMstackとは
JavaScript、APIs、Markupの頭文字を取ってJAMと定義されています。しかし、内容としては厳密にあれを使いなさい、これを使いなさいということではなく、JavaScriptでAPIへアクセスしてデータを取得し、HTMLとして事前にビルドされた状態でサーバーに依存しない作り。というものになります。APIのデータを読み込んでJavaScriptを使い静的なHTMLとして作ることができれば、フレームワークは使っても使わなくてもJAMstackということになります。
SPA、SSRとの違い
JAMstackの一番の肝であるSSGは、SPA、そしてSSRとどのように違うのかを少し解説します。
SPAの特徴は、一つのHTML上でJavaScriptを使い、要素を切り替えてあたかもページ遷移しているかのように見せています。
しかし、ページとしては一つのHTMLしかありませんので、OGPなどはブラウザ上でJavaScriptが動作しなければ切り替えられません。
SSRの特徴は、SPAの問題でもあったOGPなどの切り替えを行えるようにHTMLをサーバーサイドで生成します。
ブラウザではSPAと同様の動作を行い、SNSシェアなどのロボットに対してはサーバーサイドのHTMLを提供します。
しかし、サーバー側で生成するコストがかかります。
そしてSSGの特徴は、SSRのサーバーサイドで生成する部分をあらかじめローカルで行ってしまうことで、サーバー側のコストをなくす手法になります。
メリットデメリット
メリット・デメリットをまとめますと下記になります。
SPA
メリット
- 通常のWebページでは実現できないユーザー体験。
- 高速なページ遷移。
- ネイティブアプリの代用。
デメリット
- 初期ローディングにかかる時間が増える。
- OGPなどのページ情報を外部へ連携しづらい。
- ユーザーのデバイス環境に依存してしまう。
SSR
メリット ※SPAのメリットは引き継がれます。
- 初期ローディングにかかる時間が少ない。
- ユーザーのデバイス環境に左右されにくい。
- OGPなどのページ情報を外部へ連携できる。
デメリット
- サーバー側の負担が増える。
- Node.jsを実行できるサーバーが必要になる。
SSG(JAMstack)
メリット ※SSRのメリットは引き継がれます。
- SSRよりも初期ローディングにかかる時間が少ない。
デメリット
- 外部データが更新されたタイミングで再ビルドを行わないと変更は反映されない。
- 動的なデータが頻繁に変更される場合は向かない。
JAMstackの問題点と解決
メリット・デメリットを見ますと概ねJAMstack構成が素晴らしいものに見えてしまいますが、デメリットにもある通り、問題点がないわけではありません。
外部データが更新されたタイミングで再ビルドを行わないと変更は反映されない。
この問題に関して、どこがどう問題なのかを簡単に説明しますと、ローカルのPCなどで動作させることができてはじめてHTMLが生成できるので、外部データを取得してHTMLを生成する環境が必要になるということです。
ですが毎回ローカルのPCで開発者がHTMLを生成していては更新のタイミングが自由にできませんよね?
そういうった問題を解決するのがCIツール(継続的インテグレーション)になります。
今回はCIツールとしてGitからもCMSからも操作しやすいGithub Actionsを利用しました。
図のように機能開発や改修のパターンでもCMSの更新のパターンでも、Github Actionsを通してビルド&デプロイすることでJAMstackの課題でもある部分をオートメーション化しました。
さらにGithub Actionsのタスクで、デプロイされた時にはチャットで通知するようにもしました。
Nuxt.jsでのポイント
Nuxt.jsとは
Vue.jsベースの公式ライブラリを含む強力な開発ツールをバンドルしたJavaScriptフレームワークになります。
同じようなフレームワークでReactベースのNext.jsなどがあります。
メリットデメリット
Nuxt.jsのメリットは状態管理ライブラリがデフォルトでインストールされ、フォルダ構造もきちんと作られます。
またルーティングも基本的に自動で作られるので、ファイルを作ってコーディングをすれば自ずと出来上がっていきます。
またVue.jsベースなので状態管理や機能などの書き方がほぼルールとして存在しています。
テンプレートの書き方に関してもHTMLにVue用の属性を書いていくようなかたちなので、複数人での作業の場合にロジック部分の共有をメインにすることが簡単になります。
ただし、これに関してはReactであってもルールと熟練度でクリアできる部分とは思います。
デメリットは、Next.jsなどReactベースのフレームワークと比べるとコードのシンプルさが劣ると思います。
また、ルールがあることによって回りくどく実装しなければならない部分も多少あります。
この辺りは次のバージョンで多少改善されるそうです。
個人的には、熟練したチームでコーディングルールなどが浸透している場合にはReactベースのNext.js。
これから始めるのにルールは設けたいけどハードルは低くしたいという場合にはNuxt.jsがおすすめです。
気をつけるべきポイント
最初からNuxt.jsではじめる
今回フロントエンドの開発では役割を「静的テンプレートの作成」「Nuxt.jsへの組み込み」に分担し「静的テンプレートの作成」は慣れと速さを最優先でejsベースのテンプレートで作成を進めました。
最初の時点でコンポーネントを意識しておけばのちにNuxtで組み込む時に各パーツをわけやすくなると考え、なるべく細かくパーツを分ける方針で進めましたが、実際にはただ表示させるだけのような領域も分割してしまっていたりと無駄な作業が発生していました。
JavaScriptにおいても、主に振る舞いの部分となるUI動作「ボタンを押したらメニューが開く」「ハンバーガーメニュー」「スクロール量に応じた表示非表示」などがそのままでは適用できない、非同期遷移を考慮できていない、などNuxtに合わせて書き直す部分がありました。
可能であれば振る舞いや見た目部分からNuxt.jsをベースに作業を進めるられると無駄な変換作業や再実装の手間が減りますし、コードの意図も読みやすく作業者間での確認もしやすくなり工数が最小限に抑えられると思います。
ジェネレートを考慮
動的ルーティングをしたい場合はデフォルトのままだとHTMLを生成してくれないので、APIからあらかじめURLとなるリストを取得(もしくは自前でjsonなど用意)し、それを元に全てのページを生成する必要があります。
また、generateには以下のような大きな懸念もあります。
- generateする時にすべてのHTMLを生成するのでページが増えれば増えるほど時間がかかってしまう。
※Nuxt v2.13から自動的に動的ルーティングを検出し、ジェネレートの速度も改善しました。
現状は200〜300程度のページ数でも、運用していくにつれ1000〜2000と増えると…すごく時間がかかってきてしまいます。
継続運用していくにはコンテンツごとにシステムを区切ったり、更新したページ分のデータのみでHTMLを生成し、独自にスクリプトを組んで生成した分のHTMLを追加配置するような作りにしなければなりません。
このように運用を見越した作りを最初から想定して構築するのは簡単なことではありませんが、
一度プロトタイプを作って試してみるといいかもしれません。
Firebaseでのポイント
サーバーレスって?
今回サーバーはGoogleのサービスでもあるサーバーレスのFirebaseを選択しました。
サーバーレスを簡単にいいますと、サーバーが常に起動してるわけではなく、必要に応じて起動し、単機能を実装して起動させることができるクラウドのアーキテクチャになります。
しかし今回はStaging環境では認証などの機能を利用してはいますが、Production環境ではその単機能さえ不要であり、ホスティング部分のみを使用しています。
レンタルサーバーやVPSの様にアクセスの集中があるとサーバーがパンクするということもなく、JAMstackにおいては有効なホスティングかと思います。
こういったサーバーレスのサービスはFirebaseの他にもAWSやAzureやIBM等でもありますし、GCP(Google Cloud Platform)でも可能です。
また静的ホスティングだけで考えた場合にはNetlifyやVercelやGithub Pagesといったサービスも利用できます。
気をつけるポイント
今回はStaging環境で認証機能をつけたりと単純に静的ホスティングだけが目的ではなかったのと、GCPへのスケールがしやすくかつ会社としても利用しているサービスの方が好ましかったのでFirebaseを選択しました。
しかしFirebaseは手軽に利用できる反面いくつかの問題点もありました。
例えばキャッシュコントロールが静的ホスティングではできなかったり、
Functionsの機能に対する無料プランの制限などで思っていたよりもすぐに制限に引っかかってしまいました。
これらはプランを上げたりGCPに移行すればもちろん問題ないのですが、場合によっては別のサービスの方がうまくいくこともあるので、利用したい機能がどのくらいのことを行う必要があるのかということを念頭に選択した方が良いです。
HeadlessCMSでのポイント
HeadlessCMSとは
冒頭でも簡単に説明しましたが、HeadlessCMSとは、フロント部分がなくAPIが作れるCMSという感じです。
WordpressやMovableTypeなどと同じように管理画面があり、そこではAPIの設定なども行えますし、記事データの入力もできます。
そしてプレビューやデプロイなどの設定もWebhookとして設定することが可能であり、
外部やフロントへの接続部分が全てコラボレーション前提で作られています。
microCMS
今回は国産サービスでもあるmicroCMSを使用しました。
このUIや説明が全て日本語という安心感もあるのですが、外部と接続するWebhookがGithub Actionsへ簡単に連携できたり、チャットの通知なども簡単に行うことができたため選びました。
また、その他のHeadlessCMSのサービスは無料枠では記事数に上限があったため、どれくらいのデータ数になるのかという部分で不安でもあったんですが、microCMSは登録数も取得量も無制限というのも安心できる部分です。
API構造
しかし今回はRDBなどであれば簡単に出力できるデータがHeadlessCMSでは取得することができず、フロント側でAPIのデータを元に算出するような実装になってしまった部分がありました。
サイトの仕様によってはAPI構造の自由度やRDBのようなリレーションをさせる部分のロジックなどが必要になる場合があるため、CMS選びは慎重に行なった方が良いです。
また、microCMSはREST API形式でしたが、サービスによってはGraphQLが扱えたりするものもあり、データ自体を最適化できるようにも構築できると思いますので、そういった点も比較検討した方が良いと言えます。
更新者のUXに注意
CMS選択で決め手になる部分としては更新のしやすさなどもあると思います。
microCMSは日本語のUIでスマートなUIなので見た目的なUXは高いですが、
エディタの機能なども重要です。
今回、構築終盤になってエディタの機能が足りないという話になり、どうにか実装できる方法をCMSの設定などで模索するという状態になってしまいました。
そういった視点で他のサービスを見てみると、高機能なものや、入力がスムーズに行いやすいなど、料金の比較だけでは見えない違いがあります。
一つのメリットにとらわれずに様々な視点で行うことで、開発者も更新者も良いUXのCMSを選ぶことができると思います。
今後に向けて
まずはリリースができましたので一段落ではあるのですが、改善するポイントなどが色々ありますし、機能追加なども行う予定です。
そういった継続してサイトを見ていく、ということもクライアントワーク同様に行なっていきたいと思います。
クライアントワークで今回のようなサイトを構築する場合には、制作期間という部分で多少コストが高くなりやすいのですが、今回構築するにあたって得た知識やコツなどをフィードバックし、より効率的にクオリティの高いものを作っていけるようにしたいと思っています。