当サイトを最適な状態で閲覧していただくにはブラウザのJavaScriptを有効にしてご利用下さい。
JavaScriptを無効のままご覧いただいた場合には一部機能がご利用頂けない場合や正しい情報を取得できない場合がございます。
承知しました
本サイトではWebサイトのエクスペリエンスを向上させるために、Cookieを使用しています。Cookieはブラウザの設定から無効にできます。本サイトで使用するCookieについては、プライバシーポリシーをご確認ください。

Blog

ブログ

開発者向け

Jamstackサイトのコンテンツ変更によって引き起こされる本番エラーを回避する方法

By Ondrej Polesny  

本番環境に関するWebサイトの一部のページでエラー500が返されます。理由はわかりません。最近のコード変更はないため、コンテンツの更新に接続する必要があります。

この記事では、コンテンツの変更によってWebサイトが破損する可能性があることと、CIがこれらの障害によって引き起こされる停止を回避するのに実際にどのように役立つかについて説明します。この記事の範囲では、JavaScriptベースのWebサイトに焦点を当てますが、原則はどの言語にも適用できます。

実装の制限

私たち開発者は、制限されるのが好きです。 Webアプリケーションを実装するときは、コーディング中またはビルド時に潜在的な問題をできるだけ早く発見できるように、タイプセーフな言語を使用します。ユニットテストと統合テストを追加して、変更に副作用がなく、すべてが機能し続けることを確認します。

ただし、すべてのWebサイトには、コードとコンテンツの2つのコンポーネントがあります。上記の対策により、コード部分に自信が持てますが、コンテンツについてはどうでしょうか。

確かに、きめ細かく定義されたコンテンツモデルがあり、すべてのコンテンツタイプを慎重に準備し、リンクされたアイテムとリッチテキスト要素でのコンテンツアイテムの使用を制限し、権限のないユーザーがコンテンツタイプを変更できないように役割を定義しましたが、それでも—それで十分?それはまた私たち自身から私たちを守りますか?

KenticoによるKontentの監査ログ

これは、Kontent.aiWebサイトコンテンツモデルへの最新の変更を示す監査ログのスクリーンショットです。ご覧のとおり、特に大規模なWebサイトでは、モデルの変更はそれほど珍しいことではありません。私たちの場合、それらはすべて、プロジェクトの主任開発者である1人の人物によって、別の環境で実行されました。ただし、これらすべての変更で実装を最新の状態に保つために、1人の開発者、さらに悪いことに複数の開発者に依存するリスクが存在することを示しています。

強く型付けされたコンテンツと構造を追加する

起こりうる最悪の事態は何ですか?壊れたビルドについて考えているのであれば、それは最も問題ではありません。ビルドが失敗した場合は、何かが間違っていることがわかります。一部のページがエラー500を返し始めたり、他のエラーを表示したり、コンテンツが欠落している場合でも正常に動作したりすると、さらに悪化します。実行時の問題は見つけるのが難しいため、最悪です。

では、どのように状況を解決するのでしょうか。

生成されたコードネームの使用

まず、タイプミスやコードネームの変更によって生じるエラーを軽減する必要があります。新しいJavaScriptDelivery SDKにより、モデルジェネレーターが大幅に更新され、すべてのコードネームを含むプロジェクト構造を生成できるようになりました。以前は、ブログ投稿の一般的なコンテンツクエリは次のようになりました。

 const blogPosts = await deliveryClient .items() .type( 'blog_post' ) .orderByDescending( 'elements.date' ) .limit( 3 ) .toPromise()

新しいバージョン11では、生成されたプロジェクト構造を使用すると、次のようになります。

 const blogPosts = await deliveryClient .items() .type(projectModel.contentTypes.blogPost.codename) .orderByDescending( `elements. ${projectModel.contentTypes.blogPost.elements.date.codename} ` ) .limit( 3 ) .toPromise()

これにより、タイプミスとコードネームの変更の両方が解決されます。

生成されたタイプを最新の状態に保つ

コンテンツ収集クエリを進めると、返されたアイテムはBlogPostタイプにマップされます。生成されたタイプがヘッドレスCMSの対応するコンテンツタイプBlogPostで最新である限り、それを使用するすべてのページとコンポーネントはタイプの安全性の恩恵を受けることができます。

これは、すべての本番ビルドの前に型を再生成することで実現します。

ヘッドレスCMSは、コンテンツモデルと生成されたタイプの信頼できる情報源です。サイトの実装ではありません。ただし、開発者はすべての変更を追跡するのが好きで、生成された型をソース管理でコミットしたいと考えています。

したがって、タイプの不一致を発見するために、本番ビルドパイプラインにチェックを組み込みます。一時フォルダーに新しいタイプのセットを生成し、実装にあるタイプに対して単純なディレクトリ差分を実行します。

まず、比較を処理するdir-compareモジュールをインストールします。

 npm i dir-compare --save-dev

次に、次のようなノードスクリプトverify-types.jsを追加します。

  • Kontentの現在のコンテンツモデルからタイプを生成します
  • それらを追跡されたタイプと比較します
  • 違いがある場合はビルドを停止します
const { mkdirSync, rmdirSync } = require('fs');
const { generateModelsAsync } = require('@kentico/kontent-model-generator');
const dircompare = require('dir-compare');
require('dotenv').config();

async function verifyModels(existingTypesFolder){
    console.log('Verifying content model...');

    const date = new Date();
    const tempFolderName = `tmpModels${date.getFullYear()}${date.getMonth()}${date.getDate()}${date.getHours()}${date.getMinutes()}${date.getSeconds()}`;

    // create temp folder and generate types
    mkdirSync(tempFolderName);
    process.chdir(tempFolderName);
    await generateModelsAsync({
        sdkType: 'delivery',
        projectId: process.env.KONTENT_PROJECT_ID,
        addTimestamp: false,
    });
    process.chdir('..');

    // compare generated types with existing types
    const diff = await dircompare.compare(existingTypesFolder, tempFolderName, {
        compareContent: true,
    });

    rmdirSync(tempFolderName, { recursive: true });

    if (diff.same){
        console.log('Content model is unchanged.');
        return;
    }

    console.error(`There are ${diff.differences} differences:`);

    diff
        .diffSet
        .filter(i => i.state !== 'equal')
        .forEach(d => console.error(d));

    console.error(`Content model contains unexpected changes. Regenerate the types in your project.`);
    process.exit(1);
}

const existingTypesFolder = process.argv[2];
verifyModels(existingTypesFolder);

注:プロジェクトでモデルジェネレーターの構成を調整した場合は、スクリプトでも同じように構成してください。

スクリプトは、単一のパラメーター、つまり生成されたタイプのディレクトリーへのパスを想定しています。

 node ./verify-types.js {directory of your generated types}

スクリプトがプロジェクトのルートレベルにあることを確認し、 package.json本番ビルドスクリプトを調整します。

 { ...  'scripts' : { ...    'build' : 'node ./verify-types.js {directory of your generate types} && next build' , } }

注:私のプロジェクトはNext.jsに基づいているため、ビルドスクリプトが異なる場合があります。

実稼働ビルドでモデルを検証するだけでよいことを忘れないでください。 npm run devを実行するよりも頻度が低いため、手動で行うのは問題ありません。

ビルドの失敗=問題の回避

これで、コンテンツが変更され、本番環境の完全または部分的な再構築を行う必要がある場合、ビルドサーバーは最初に型を生成し、実装で追跡する型と比較します。違いがある場合、ビルドは失敗し、違いを正確に示すエラーが表示されます。

注:この場合、 Block with imageのコンテンツタイプBlockが変更されました。

問題を解決するまで、本番サイトは変更されません。

注:コードでプロジェクト構造定数を使用する場合、コードネームを変更しても、無害であってもビルドが停止します。私も個人的にこれらの変更について知りたいのですが、verify-models.jsスクリプトを更新して無視してください。

結論

この記事では、コンテンツモデルの変更が本番Webサイトにどのように危険であるかを示し、本番ビルドのたびにヘッドレスCMSを使用してコンテンツの生成モデルとプロジェクト構造を確認することを提案しました。この手順により、安全性が高まり、最も傷つく可能性のある予期しない問題を回避できます。

以下のリソースへのリンクを見つけて、ヘルプが必要な場合やプロジェクトの詳細について話し合いたい場合は、Discordのコミュニティに参加してください。

資力:

Headless CMSの導入をお考えでしょうか?

クラウドとマルチデバイスに最適化されたKentico Kontentをお試しください