運用中サイトのスキーマ変更
このページで分かること
- サイトで起きる4つの作業(コンテンツの編集、コードのデプロイ、初回の構築、スキーマの変更)と、それぞれが変える範囲
- 管理画面とCLI(
emdash schema)による運用中のスキーマの変更と、変更後のTypeScriptの型の再生成 - シードファイルを本番のモデルに合わせる方法、プレビュー環境での予行演習、誤って変更したときの復旧
このページの目次
EmDashは、コレクション、フィールド、タクソノミーを、コンテンツと同じデータベースに保存します。このガイドでは、運用中のこのコンテンツモデルを変更する方法を説明します。コードのデプロイ、初回のシード、EmDashのコアマイグレーションとは区別して扱います。例ではCloudflare D1を使いますが、同じ区別はすべてのデータベースアダプターに当てはまります。
どの作業が何を変えるか
サイトでは、4つの異なる作業が発生します。それぞれが変える層は異なります。
| 作業 | 変わるもの | 方法 |
|---|---|---|
| コンテンツの編集 | エントリー、メディア、設定 | 管理画面またはコンテンツAPI |
| コードのデプロイ | テンプレート、設定、EmDashのバージョン | wrangler deploy。EmDashが管理するデータベースのテーブルをマイグレーションすることがあります |
| 初回の構築 | 空の状態からすべて | マイグレーション+シードファイル+セットアップウィザード。最初の起動時に自動で実行されます |
| スキーマの変更 | コレクション、フィールド、タクソノミー | 運用中のサイトに対して管理画面または emdash schema を使います(このページ) |
シードファイルが関わるのは3行目だけです。シードファイルは、データベースが空で、セットアップウィザードが完了していないときに1回だけ適用されます。既存のデータベースに対して変更したシードファイルをデプロイしても、何も起きません。運用中のサイトのスキーマの変更は、常に管理画面またはAPIを通して変更します。
やさしい解説
WordPressでは、カスタム投稿タイプやカスタムフィールドの定義は、テーマやプラグインのPHPのコードに書かれていることが多く、コードを更新すれば定義も変わります。EmDashでは、コレクションとフィールドの定義はデータベースに保存されています。そのため、シードファイルを書き換えてデプロイしても、すでに動いているサイトのコレクションやフィールドは変わりません。運用中のサイトの定義は、管理画面か emdash schema コマンドで直接変更します。
管理画面でスキーマを変更する
デプロイしたサイトのスキーマを変更する主な方法は、管理画面です。管理画面で 「コンテンツタイプ」 を開き、コレクションとフィールドを追加、編集、削除します。変更はすぐに反映されます。コンテンツAPI、ローダー、編集画面は、どれも実行時にデータベースからスキーマを読み込むためです。
使えるフィールド型、検証ルール、ウィジェットのオプションについては、コレクションとフィールドを参照してください。
スキーマを変更した後は、テンプレートが使うTypeScriptの型を再生成します。emdash types コマンドは動作中のインスタンスからスキーマを読み込むため、デプロイしたサイトを直接指定できます。
npx emdash types --url https://example.com
CLIでスキーマを変更する
emdash schema コマンドは、動作中のインスタンスとREST API経由でやり取りするため、ローカルの開発環境と同じように、デプロイしたサイトに対しても使えます。デバイスフローで一度認証します。
npx emdash login --url https://example.com
代わりに、管理画面の 「設定」→「APIトークン」 でAPIトークンを作成し、--token または環境変数 EMDASH_TOKEN で渡すこともできます。CIではこの方法が便利です。
その後、ローカルで使うのと同じコマンドでスキーマを変更します。
npx emdash schema add-field posts subtitle --type string --label "Subtitle" --url https://example.com
npx emdash schema remove-field posts legacy_field --url https://example.com
npx emdash schema create projects --label Projects --url https://example.com
これらのコマンドをスクリプトにしてリポジトリに入れておくと、各環境に同じ順序で同じ変更を加えられます。ただし、コマンドは自動で冪等にはなりません。すでに存在するオブジェクトに対して create や add-field を再実行すると、失敗することがあります。emdash schema list または get で対象を調べ、どの環境でどの手順が完了したかを記録し、最初のエラーで止めます。
コマンドの一覧は、CLIリファレンスを参照してください。
シードファイルを同期させる
ビルドに埋め込まれるシードファイルは、新しいデータベースを何で初期化するかを決めます。新しいプレビュー環境、障害から復旧するための再構築、同じサイトの2つ目のデプロイがこれに当たります。本番のモデルが別のものに変わっているのに、シードがstarterのブログのままだと、新しい環境はすべて誤ったモデルで構築されます。
ビルドは、.emdash/seed.json、package.json#emdash.seed に書かれたパス、seed/seed.json のうち、最初に見つかったシードファイルを埋め込みます。どれもない場合は、組み込みの既定のシード(starterのブログのモデル)が埋め込まれ、astro dev が警告を出力します。
デプロイしたサイトのスキーマを変更した後は、運用中のモデルをリポジトリにエクスポートし直します。emdash export-seed はローカルのSQLiteファイルを読み込み、wrangler d1 export はデプロイしたD1データベースからそのファイルを作ります。
npx wrangler d1 export emdash-db --remote --output=./prod.sql
sqlite3 prod.db < prod.sql
npx emdash export-seed --database prod.db > .emdash/seed.json
エクスポートしたシードには、運用中のサイトの設定、コレクション、タクソノミー、メニュー、ウィジェットエリアが含まれます。エントリーも含めるには、--with-content を追加します。更新した .emdash/seed.json は、新しいスキーマに依存するコードと一緒にコミットします。こうすると、新しい環境が常に、コードが理解できるモデルで構築されます。
やさしい解説
シードファイルは、WordPressでいえば「新しくサイトを作ったときに最初から入っている投稿タイプやカスタムフィールドの設定」にあたるものです。運用中のサイトで管理画面からフィールドを追加しても、リポジトリのシードファイルは自動では変わりません。そのままだと、新しいプレビュー環境などを作ったときに古い構成で作られてしまいます。そのため、本番のデータベースから emdash export-seed でシードファイルを作り直し、コードと一緒にコミットします。
プレビュー環境で変更を予行演習する
破壊的なスキーマの変更(フィールドの削除、コレクションの再構成)は、本番の使い捨てのコピーで予行演習するのが最も安全です。
-
別のプレビュー用のD1データベースを作成し、Wranglerに
preview環境へ追加させます。npx wrangler d1 create emdash-db-preview \ --binding DB --env preview --update-configenv.preview.d1_databasesに、新しいデータベースの名前とUUIDが含まれていることを確認します。バインディングは、Wranglerの設定の最上位からは引き継がれません。 -
本番をエクスポートし、プレビュー環境の
DBバインディングを通してそのSQLをインポートします。npx wrangler d1 export emdash-db --remote --output=./prod.sql npx wrangler d1 execute DB --env preview --remote --file=./prod.sql -
プロジェクトをビルドしてプレビュー環境にデプロイし、プレビューのURLに対してスキーマの変更を実行します。
npm run build npx wrangler deploy --env preview npx emdash schema remove-field posts legacy_field --url https://preview.example.com -
公開ページ、管理画面のフォーム、生成された型、変更したフィールドを読み込むテンプレートを確かめます。本番のデータベースのバックアップを新しく取り、同じコマンドを本番に対して1回実行します。
誤った変更からの復旧
- フィールドを誤って削除した。 列とそのデータは、運用中のデータベースから失われています。D1のTime Travelによる特定時点のバックアップから復元するか、フィールドを追加し直して、以前の
wrangler d1 exportから値を復元します。 - 新しい環境が誤ったモデルで構築された。 埋め込まれたシードが古いか、存在しませんでした。
.emdash/seed.jsonを更新し(シードファイルを同期させるを参照)、ビルドし直して、デプロイの接続先を空のデータベースにして構築し直します。 - スキーマとテンプレートが一致しない。 デプロイとスキーマの変更は互いに独立しているため、順序を意図して決めます。追加のスキーマ変更(新しいコレクション、新しい省略可能なフィールド)を先にし、それを使うコードを後にします。削除の場合は、先にそのフィールドを使わなくなったコードをデプロイし、その後でフィールドを削除します。
やさしい解説
スキーマの変更とコードのデプロイは別々に実行されるため、順番を間違えるとテンプレートがエラーになります。フィールドを増やすときは「フィールドを追加 → そのフィールドを使うコードをデプロイ」、フィールドを消すときは「そのフィールドを使わないコードをデプロイ → フィールドを削除」の順にします。