
はじめに
公開サイトのセキュリティの向上とスケーラビリティの観点から、CMSで構築したサイトをCDN上の静的サイトとしてデプロイするサイト運用が昨今非常に注目されています。そのツールとしてのSSGも老舗のJekyll, Hugoから最近急成長のGatsbyまで多種多様です。
SSGによるサイト公開までの流れは、
- コンテンツのソースとなるMarkdownファイルやHTMLファイルの作成
- サイト生成のための設定ファイル、テンプレート、CSS、画像などの準備
- これらのデータからSSGがデプロイ用のディレクトリに静的サイトを生成
- デプロイ用のディレクトリをCDNや公開用サーバーにアップロード
が基本です。さらに最近ではソースとなるMarkdownファイルなどの代わりにDrupalやWordPressのコンテンツをソースとするSSG用のプラグインも提供されています。
一方Drupal本体にSSGの機能を持たせるというアイデアもあり、その実装としてTomeというモジュールがまだベータ版ですが公開されています。静的サイト生成についてはStatic GeneratorというモジュールもありますがDrupal8に対応していないためその代替としてTomeがどこまで使えるか検証しました。
テスト用のサイトとしては最近のDrupal8のインストレーションプロファイルにあるUmamiというプロファイルで生成されるレシピ集のデモサイトを使いました。Umamiについては「ANNAIマガジン」の記事「Drupal 8のデモ用インストールプロファイルUmami を日本語化してみた」に詳しい解説があり、日本語化した画面も紹介されていますが、その画面とTomeで生成した静的サイトとして今回公開したデモサイト https://umami-static.work/ を比較するとかなり忠実に生成されており十分実用に耐えるものとなっています。
インストレーション
Tomeモジュールは2018/12/23公開のhttps://www.drupal.org/project/tome/releases/8.x-1.0-beta2/ を使用しました。
https://dev.acquia.com/downloads/ からダウンロードしたAcquia Dev Desktopをインストールした以下の環境を用いてテストしました。
- OS macOS Mojave 10.14.2
- Drupal 8.6.2
- MySQL 5.6.41
- PHP 7.2.9
- Apache 2.4.29
モジュールのインストールは機能拡張のページから通常の手順で行いました。
モジュールの有効化後は以下の機能拡張が追加されます。
静的サイトの生成
サイトの生成はとっても簡単です。
環境設定に追加された以下のメニューから「Generate static site」を選択します。
選択後表示される以下の画面で送信ボタンをクリックするとあらかじめ設定されたディレクトリに静的サイトに必要な全てのファイルが書き出されます。
デフォルトでは../htmlというドキュメントルートの外のディレクトリに出力されます。(このディレクトリはsettings.phpで変更出来ますが、ドキュメントルートの下のディレクトリを指定するとそのディレクトリからさらに静的サイトを作成しようとしてループ状態になり、エラーが発生するので注意してください)
なお、同じことは
drush tome:static
コマンドでも実行できるので、コンテンツ更新をトリガーにこのコマンドで静的ファイルを生成し、さらにそれを公開用サイトにデプロイするスクリプトを実行することも可能です。(https://tome.fyi/docs/sub-modules/ によれば将来的にはtome:static:watchというオプションが追加されサイトの変更を監視してバックグラウンドで自動的に静的サイト生成を行えるようになる可能性があります)
サイト生成処理は差分更新ではなく全サイト生成なので大規模サイトでは相応の時間が必要となりそうです。生成時間を重視するならば同じ全サイト生成でもかなり高速なGatsbyと連携するというアイデアもあり、後でもう少し詳しく説明します。
静的サイトの特徴と制約
Umamiのようなカスタムコンテンツタイプやそのビューを含むサイトであってもかなり忠実に再現されています。レスポンシブデザインも維持されていますし、タクソノミーのターム別ページも再現されています。デモ用に生成したhttps://umami-static.work/ のサイトで確認することができます。またページネーションや多言語サイトでの言語切替が動作することも別のテストサイトで確認しました。下図は日英の言語別コンテンツ切り替えのサンプルです。
ただし変換が忠実すぎて静的サイトでは実行できないフォームを持つブロックやそのフォームへのリンクまで生成されます。従って静的サイトを意識して以下のような要素とそれらに関連するブロックやリンクなどを、生成前に非表示または無効にしておくことが必要です。
- ログインフォーム
- 検索フォーム
- メール問合せフォーム
- ビューの持つフィルターやソート機能
なお、これらの制約にどのように対応するかは後述します。
Tomeモジュールの詳細なドキュメントはhttps://tome.fyi/docs/ に公開されておりその中のhttps://tome.fyi/docs/technical/static/ にサイト生成のロジックが解説されています。概略は以下のとおりです。
1. 匿名ユーザーからアクセスできる全てのルート(route)及び全エンティティ(さらにそれらの翻訳)の標準化されたパスで、パラメーターを使用していないものを収集します。
2. パスについては以下のように処理します。
a. パスが静的ファイルの場合はそのままコピーします。
b. 静的ファイルでないパスについてはDrupalのhttp.kernelサービスを呼び出します。
c. レスポンスがHTMLの場合はそれをファイルとして保存します。
さらにその中で参照する種々のアセットのパスを収集します。
現在のバージョンではViewsのpager link、イメージ、CSS、JavaScript、faviconが対象になります。
CSSの場合はさらにその中のurl()で参照されているURLもアセットのパスに追加します。
3. 新たに追加されたアセットのパスについて上記2.の処理を行います。これを新たなアセットがなくなるまで繰り返します。
このロジックにより多言語サイトや任意のコンテンツタイプやビューにも対応できることが理解できます。
Drushを使ったインストレーション
https://tome.fyi/docs/getting-started/ には「Tomeは既存のサイトにもインストールできるが、専用のDrupalコンフィグレーションを用いてインストールするのがベストである」という記述があり、ComposerとDrushを用いてTomeがインストールされた新規サイトを作成する手順が解説されています。
そこでこのページにあるスクリプトをUbuntu 18.04の環境で以下のように実行して動作を確認しました。
インストール後にUmamiサイトのテストに用いたAcquia Dev Desktopのサイトのsettings.phpとこのDrushでインストールしたサイトのsettings.phpを比較したところ、後者のサイトはデフォルトでSQLite3のデータベースを用いる設定が追加されている以外は違いが見当たりませんでした。さらに管理>>Reports>>Status reportを比較したところ後者のPHPメモリ制限が無制限になっているところが目立った違いでした。もしこのメモリ無制限の設定がTome用の最適な設定の主要な部分ということであれば、Drushを使用せずに通常の方法でTomeモジュールをインストールしてからメモリ無制限の設定に変更するだけでも大差はないとも考えられます。
Gatsbyとの連携
ReactベースのSSGとして急成長しているGatsbyとTomeとの連携のサンプルが公開されています。このページの手順に従ってUbuntu 18.04上に新たにDrupalとGatsbyのプロジェクトを作成してDrupalをソースとしてGatsbyで静的サイトを生成しました。サイトのサンプルはhttps://tome-gatsby-sample.now.sh/ にあります。
通常GatsbyとDrupalの連携には、DrupalのJSON:APIモジュールを経由してコンテンツを取得するgatsby-source-drupalというGatsbyのSource pluginを使用します。しかし、このサンプルはTomeモジュールでDrupalコンテンツを一旦JSONファイルに変換して保存し、そのファイルをgatsby-transformer-jsonという別のプラグインによって静的コンテンツに変換しています。この外部APIを呼び出す代わりにファイルから読み込む手法を採ることで、「gatsby develop」コマンドでGatsbyを開発モードで実行している場合はDrupalコンテンツの更新が即座にGatsbyに反映され、ページが自動リロードされます。また静的サイト生成時にはDrupalが実行されていなくてもよいので、フロントエンドとバックエンドの開発チームや環境を独立させることもできます。
制約事項としては
- DrupalはあくまでGatsbyへのソース提供サーバーとしてのHeadless CMSとして動作するのでGatsbyフロントエンドのテーマやリスト表示、ページネーションなどはGatsby側で実装する必要があります。
- サンプル内のGraphQLは特定コンテンツタイプのみ対応しており、かつ取得している全てのフィールドにデータがないとコンテンツが生成されません。したがって複数コンテンツタイプに対応し、かつデータのないフィールドも考慮するとより複雑な処理が必要となります。
などがあります。
数千ページから数万ページ規模のサイトではGatsbyの持つ高速なサイト生成とレンダリング時のページプリロードなどの高速化機能が活用できるので、大規模サイト構築の場合は考慮すべきオプションになると思います。
静的サイトの制約への対応
静的サイトであっても外部サービスのAPIなどを使って動的な動作を可能にするJAMstackというアプローチを参考にして「ANNAIマガジン」の記事「Drupalサイトを静的HTML(Static HTML)に変換する方法」の「静的HTMLで難しいこと」の章に列挙された制約にどこまで対応可能かを考えてみました。
- ユーザー登録とログイン
Basic認証によるログイン制限であればサイト生成後に.htaccessファイルを適宜設置するようにしておくという対応が考えられます。Netlifyではデプロイした静的サイト用の認証サービスなどもあります。これにはOAuthを利用した認証機能などもあるようです。 - コメント機能
静的サイトを閲覧した人がその場でコメントするのはコメントの入力・表示などのAPIの開発にある程度の工数が必要です。 - コンタクトフォーム
メール送信フォームの場合は、デプロイしたサイトでSMTPサーバーが稼働していれば作り込むことは可能でしょう。Netlifyではフォーム処理サービスも提供されています。 - 検索機能
静的サイトにしたときに一番の課題となる検索機能の実装についてはいくつかのアイデアがありますが詳細は別の機会に考察したいと思います。- Apache Solr
- Solrにより定期的にサイトを巡回し全文検索インデックスを作ります。
- 検索用SaaSのAlgolia
- 生成時に検索用JSONファイルを出力するためにTomeモジュールの修正が必要かもしれません。
- Googleのカスタム検索
- Gatsbyと連携させるのであればLunr.jsベースのGatsby用プラグインも提供されているので検索機能の実装が比較的容易であり、あるいはhttps://mottox2.com/posts/268 のような自力実装も可能です。
- Apache Solr
- ビューのフィルターやソート
これは難易度が高い課題です。Drupal側でフィルタリングやソートを処理するAPIを準備しておき、フロントエンドでは例えばhttps://handsontable.com/docs/6.2.2/demo-filtering.html のようなJavaScriptのGridライブラリを使ってフィルタリングやソートのUIを提供する必要があります。
またフィルタリングの条件が性別や過去数年の西暦年などの比較的固定的なものであればJavaScriptで作り込むことでも一応対応できるでしょう。 - ロールあるいはユーザー単位のコンテンツやブロックの表示制御
Basic認証を用いたユーザーに対するディレクトリ単位でのアクセス制限であれば各ディレクトリへの.htaccessの配置で対応できますが、ロールベースの制御やブロックレベルの表示・非表示などの細かい制御は難易度が高くなるでしょう。 - リアルタイムでのコンテンツ更新
一般的には難易度が高い機能です。しかしながらトランザクション処理が必要で難しそうなeコマース機能については、eコマースAPIのサービスが複数のベンダーから提供されていてGatsbyベースのeコマースサイトの解説記事もあります。商品の詳細な解説やプロモーション及びブログやヘルプ機能だけはDrupalで作成し、eコマース機能は外部API使用というようなサイトをGatsbyと連携して実現することは可能でしょう。 - スケジュール公開
Schedulerモジュールにより公開日時を設定した場合そのノードは公開日時までは匿名ユーザーからアクセスできないので、公開日時の制御が1時間単位でよければ1時間おきに、1日単位で問題なければ毎日サイト生成すれば対応できます。
まとめ
- Drupalのサイトをかなり忠実に静的サイトに再現できることを確認できました。UmamiのようなカスタムコンテンツタイプやそのViewを含むサイトにも対応できます。
- 静的サイトでは無意味なDrupalへのログインフォームまで再現するので静的サイトを意識した若干の手直しは必要になります。
- SSGであるGatsbyとの連携のサンプルも動作が確認できました。Drupalコンテンツの迅速な反映や大規模サイトの高速レンダリングが必要な場合はGatsbyとの連携も選択肢になります。
- CMSのStatic Site化は今後のトレンドになると思うので、そのツールとしてTomeは極めて有効なモジュールであることが検証できました。従来はGatsbyやHugoなどのSSGとの組み合わせが必須だと考えていましたが、サイトの再現性を確保するにはある程度の工数が必要であり、Tomeはこの点でも明らかに優れています。
関連コンテンツ
- Node.jsを用いて、REST APIで外部からDrupal8にコンテンツを投稿する
- Drupal8に記事を作成するReactアプリを作る
- Drupal 8のノードのデータ構造を見てみる (2)
- 既存のDrupalフィールドを再利用すべきか?
- CMSの第四の波 Distributed CMS (Drupal Developer Days Transylvania 2019)
- 2019年3月6日以降、Drupal 8を利用する場合はPHP7が必要です。(PHP 7.1以上を推奨)
- Drupal 7 サポート終了と長期サポートについて
- PHPTemplateとTwig themingの記法の比較
- Drupal8のテーマにスタイルシート(CSS)とJavaScript(JS)を追加する
- 2018年時点のDrupalのDocker環境事情
Drupal 8初心者講座バックナンバー
Drupal初心者講座について
第1回 歴史に見るDrupal のDNA
第2回 Drupalはフレームワークか?CMSか?
第3回 Drupalの特徴
第4回 Drupal 8のインストール(1)
第5回 Drupal 8のインストール(2)
第6回 コンテンツを投稿してみる
第7回 ボキャブラリとタクソノミーを使う
第8回 コンテンツ管理におけるDrupalと他のCMSとの比較
第9回 Drupal 8のブロックシステム
第10回 Drupalの標準クエリービルダ Views
第11回 Drupalと他のCMSのクエリビルダー機能を比較
第12回 Drupal 8の多言語機能と他のCMSやサービスとの比較
第13回 Drupalの権限設定とWordPressやMovable Typeとの比較
第14回 Drupalのテーマシステムについて
第15回 Drupalの拡張モジュールの選定と利用方法
第16回 Drupalをもっと知りたい方に向けた各種情報