PowerCMS X ブログ
2023-12-15
SSG(静的サイトジェネレーター)によって静的ファイルを生成し、AWS S3などのストレージにファイルを置いて CDNで配信する。
いわゆるサーバーレスとかモダンアプリケーションとか呼ばれるものが最近のトレンドのようですが、PowerCMSや PowerCMS Xは静的ファイルを生成するタイプの CMSですので、SSGを使わなくともこのような構成が取れます。しかも非常に高速にパブリッシュができます。
などという話があります。(私たちにとっては)何を今さら... といった感想しかありません。
そこで登場したのが「インクリメンタル静的再生成」というのだそうですが、簡単に言うと
一定時間ごとにバックグラウンドでデータの再取得およびページの再レンダリングを行い、HTML を再生成 (regenerate) する手法
ということだそうです。なるほど。
export async function getStaticProps(context) {
const entryId = context.params.id
const entry = fetchContent(entryId)
return {
props: { entryId, entry },
revalidate: 300, // <= 300秒 = 5分
}
}
5分間は生成済みのコンテンツを返し、それ以降にリクエストがあった時には再生成する、という手法のようですが、すべての SSGが同じ仕組み(上記の例は Next.js)というわけでもありません。
確かにすべてをビルド(再構築)するより効率的で無駄がない、と考えられますが、以下の課題の解決には至りません。
PowerCMS Xはこれらの問題をすべてクリアすることを目標としています。あくまでも「目標」ですが、ウェブサイト内の更新されたコンテンツと関連する部分のみをリアルタイムに更新するための細やかな設定が行えるのが特長です。
いわゆる「インデックス・アーカイブ」と呼んでいるものです。テンプレートに対するページが基本的に 1ページのみとなるものについては「再構築トリガー」を指定します。
PowerCMS Xでは、インデックス・アーカイブに限らず、再構築トリガーを指定できますし、「スコープをまたがる」か「スコープをまたがらないか」を指定できます。
1つのテンプレート(URLマップ)から複数のページが出力されるアーカイブとは、たとえば記事アーカイブ、ページアーカイブ、カテゴリアーカイブなどを指します。
このようなアーカイブに対してトリガーを指定する際には注意が必要です。
たとえば最新記事 5件をすべてのページに載せているから、といった理由はわからなくはありませんが、最新 5件目以降の記事が更新されて変化がないのに 1000ページを再構築するのは負荷が高すぎます。
※ インデックス・アーカイブを JSON出力して非同期に読み込むなどの方法を検討すると良いでしょう。
カテゴリアーカイブに対して「記事」を再構築トリガーに指定しているケースを見かけることがありますが、これもお勧めしません。以下を理解していただくと良いと思います。
再構築トリガーの設定とよく似たものに「コンテナ」という設定があります。
のような関係性を指します(PowerCMS Xは自由すぎるが故にたとえば「ページ」のコンテナに「記事」を指定することすら可能ですが)。
「カテゴリ」アーカイブのコンテキストでは、コンテナに指定された記事については、そのカテゴリに関連づいているものだけがリストアップされます(ignore_archive_context指定をしない限りは)。
この時、記事の更新と連動して更新されるカテゴリは以下のルールによります。
たとえばカテゴリを1つ指定して記事を投稿すると、カテゴリが100個あっても連動して更新されるカテゴリアーカイブのページは 1ページのみです。
たとえば既に「エンゼルス」カテゴリ指定があり、カテゴリを変更して「ドジャース」に変更した場合、「エンゼルス」「ドジャース」のカテゴリアーカイブのページが再構築されます。
こうしておけば、記事が更新(追加、更新、削除)されたタイミングで再構築されるファイルはリレーションによって関連づけられている(いた)ページのみとなって効率的です。
この、URLマップのモデルとコンテナとの関係性ですが、効率的で良いのですが再構築トリガーと異なり、問題としては以下のようなものが考えられます。
という点です。前者は例えば「情報分類」モデルを複数のモデル(例えば記事、ページ)で利用していた場合、記事とページのどちらかしか指定できません。
また、後者は、例えば記事が更新されればカテゴリアーカイブは更新されますが、カテゴリのラベルを変更して保存した時、カテゴリに属する記事は再構築されません。
この再構築トリガーとコンテナの弱点を補うのが「RebuildRelations(プラグイン)」です。
RebuildRelationsなら、それができます。例えば以下のように設定すれば実現できます。
アセットの場合は通常はアーカイブはありませんが(PowerCMS Xは自由すぎるので、アセットアーカイブをつくることは可能)、
さきほどの「ページのコンテンツの下に「このページと関連する記事一覧」というコンテンツリストを掲載したい」のようなケースでは、以下のように設定することで実現できます。
この時、さきほどのコンテナの例と異なるのは「相互の」更新を反映して再構築ができる、という点です。
いずれにしても、効率的に更新をかけたい部分のみをピンポイントで更新されるような設定ができます。尚、RebuildRelationsによる再構築もカテゴリが「エンゼルス」から「ドジャース」に変わった時に両方を再構築してくれます。
URLマップには「ファイル出力」という設定項目があります。
規定値は「静的」ですが、ダイナミック(動的)も指定できます。以下の選択肢があります。
ダイナミックは文字通り動的生成で、サイト内検索やフォーム、ログインページなどで利用します(PowerCMS Xでは、フォームや検索などのページを静的に書き出しておいて、パラメタ付きリクエストや POSTリクエストの時だけ動的にする、といったこともできます)。
静的と静的(遅延)の違いは、再構築のタイミングです。静的は管理画面からのオブジェクトの保存などの時に再構築を行いますが、静的(遅延)の場合は画面にレスポンスを返した後に再構築を行います(画面レスポンスは速くなりますが、画面上でエラーが拾えません)。
最後の「手動」はビューの編集画面で「保存と再構築」ボタンをクリックした時のみ再構築を行います。
このうち、あまり活用されていないように思えるのが「オンデマンド」と「キュー」です。
オブジェクトの保存時などには再構築を行わず、リクエストがあった時に初めてページをビルドするタイプの設定です。アクセスの少ないページやアクセスがさほど多くないのに更新が頻繁に行われるようなページで恩恵を受けられます。
この時、ビルドされたページはそのままディスクに書き出されるため、次回以降にアクセスしてきたユーザーにはそのコンテンツをそのまま返却します。「インクリメンタル静的再生成」に近いと言えるかもしれませんが、ファイルの生存期間を決めるわけではなく、ページに更新がなければファイルはずっとそのままです。
では、更新があった時どうするのかですが、再構築トリガー、コンテナ、RebuildRelationsの設定に従い、更新すべきものは更新すべきタイミングでディスクに書き出されたファイルを削除してしまいます。その後、リクエストがあった時に初めてページをビルドする、という流れになります。
コンテンツがいくら更新されてもリクエストがなければビルドは行われません。その代わりに、ページがない状態でアクセスしたユーザーは動的生成のレスポンス(つまり、少し待たされること)になります。
最後に、キューによる再構築をご紹介します。再構築キューは、CMSの管理画面でオブジェクトを保存したり再構築した段階ではファイルをビルド(再構築)せず、cronに登録されたスケジュールタスクコマンドによって再構築を行うものです。
といった場合に「キュー」を選択することになります。ポップアップウィンドウを開いて、何時間も再構築が終わるのを待つのもなかなかしんどいところがあります。ただ、頻繁に更新されるページの再構築を纏められること、管理画面操作で再構築を待たなくてもいいこと、一気に負荷を上げずに非同期に再構築ができること、などのメリットがあります。
これはもう「リアルタイムに変更が反映されない」につきると思います。この欠点を補うため、以下の環境変数を指定します(次のリリースでの機能追加)。
"save_queue_realtime": true,
これを設定することで、記事アーカイブをキューにしていたとしても、その記事を「保存」したときは例外的にリアルタイムで再構築されます。反映を待つ必要はありません。
また(これも次のリリースになりますが)、スケジュールタスクによって公開、差し替えられたコンテンツはそのタスクの処理内で再構築されることが保証されるようになります。
PHPのバッチ処理は 1つのインスタンスで長時間にわたる重たい処理を行うのにはあまり向いていません。メモリに大きなデータが溜まってくると速度が落ちていくことがあるからです。
再構築キューは、短い頻度で起動し、少しづつ繰り返して処理を実行するのがポイントです。
*/5 * * * * apache cd /home/www/PowerCMSX/ && /usr/bin/php ./tools/worker.php --task_ids publish_queue --publish_queue_limit 25
*/5 * * * * apache cd /home/www/PowerCMSX/ && /usr/bin/php ./tools/worker.php --task_ids publish_queue --sleep 150 --publish_queue_limit 25 --publish_queue_offset 25
この設定では、5分おきに2プロセス 25件づつ再構築キューを処理します。重複しないように片方は 2分半待ってから実行され、publish_queue_offset分をスキップしてから実行されます。
通常のスケジュールタスクについては、逆に --exclude_ids publish_queue を指定して、別のタスクにしておくのがポイントです。
*/10 * * * * apache cd /home/www/PowerCMSX/ && /usr/bin/php ./tools/worker.php --exclude_ids publish_queue
構築フェイズでのテンプレート修正、デザイン反映などは別にして、「反映されないときは右上の再構築ボタンから再構築してください」みたいなマニュアルを作っておけば? みたいな設定は、サイトの規模が小さければ良いかもしれませんが、巨大なメディアサイトや商品点数が莫大な ECサイトなどでは通用しません。
ビュー(テンプレート)を最適化して高速なパブリッシュができるようにするのはもちろん、関連するコンテンツの再構築連動も最適化していくようにしましょう。PowerCMS Xなら、それができます!