本文へ移動
BenriWorks Lab

連載

Codex 集中講座

15回 / 全17

15/17

ガイド公開日

Vercel に載せて、プレビューURLと本番を分ける

公開されたサイトを画面に映しながら、こちらを向いて立っている男性

Codex 集中講座の第15回。GitHub と連携させて、プルリクエストごとの確認用URLと本番を自動で作り分ける方法を扱います。環境変数の持ち方、戻し方、複数のサイトを1つのドメインに並べる設定も実例で示します

書いたものが自分のURLで見られる状態にします。第1回で「書いたものが自分のURLで公開されるまでを17回で通す」と書いた、その地点です。

この回で作るのは、公開の操作ではなく、公開が自動で起きる状態です。反映するたびに手で何かをする形にすると、忘れる日が来ます。

反映すると、自動でビルドと配信が走る

Vercel を GitHub のリポジトリと連携させると、反映のたびにビルドが始まります。操作は要りません。

出てくるURLは2種類に分かれます。

本番用のブランチへの反映は、本番のURLに出ます。それ以外のブランチへの反映は、確認用のURLに出ます。プルリクエストを作ると、その画面に確認用URLが並びます。

この2つが自動で分かれることが、第8回で作った「止まる場所」に実物を持ち込みます。差分を読むだけでなく、動いている画面を見てから反映を決められるようになります。AIに書かせた変更では、この差が大きく効きます。コードを読んで問題なさそうでも、開いてみると表示が崩れていることはあります。

Vercelのデプロイの分岐を示した図。作業ブランチへの反映は確認用URLへ、本番用ブランチへの反映は本番URLへ自動で分かれることと、プルリクエストの画面に確認用URLが並ぶことが示されている
ブランチによって行き先が変わる。操作は要らない

確認用URLを検索結果に出さない

自動で割り当てられるURLは、そのままだと誰でも開けます。索引にも入り得ます。

BenriWorks では、自動で割り当てられるドメインからの応答にだけ、検索避けの応答ヘッダを付けています。実際の設定です。

{
  "headers": [
    {
      "source": "/(.*)",
      "has": [{ "type": "host", "value": "(.*)\\.vercel\\.app" }],
      "headers": [{ "key": "X-Robots-Tag", "value": "noindex" }]
    }
  ]
}

条件のところで、応答するホスト名を見ています。自動で割り当てられるドメインのときだけ、検索避けが付きます。本番のドメインには付きません。

公開してよいものだけが索引に入る状態を、設定で作っておく。これも、判断の機会を減らす仕組みのひとつです。

環境変数は、環境ごとに別の値を持つ

APIキーや接続先のURLは、環境ごとに違います。本番と確認用で同じデータベースを見ていたら、確認のつもりの操作が本番を壊します。

Vercel では、本番、確認用、手元の開発の3つに分けて環境変数を持てます。同じ名前で違う値を入れられるので、コード側は環境を意識しません。

第7回で書いたとおり、鍵はリポジトリに入れません。ここで管理します。手元で使う値は、.env.local のような追跡しないファイルに置きます。

ビルドが落ちたときの読み方

反映したのに反映されていない、という状況の原因はたいていビルドの失敗です。デプロイの記録を開くと、ビルドの出力が全部残っています。

第13回の自動検査との違いをはっきりさせておきます。GitHub Actions は検査、Vercel はビルドと配信です。検査が通ってもビルドが落ちることはあります。環境変数が足りない、ビルド時にしか動かない処理が失敗した、といった原因です。

逆に言うと、GitHub Actions のワークフローに npm run build を入れておけば、その多くはプルリクエストの段階で分かります。第13回の例で最後にビルドを置いていたのは、そのためです。

戻し方を先に決めておく

本番で問題が見つかったときの手順を、問題が起きる前に決めておきます。

Vercel には、過去のデプロイへ切り替える操作があります。ビルドをやり直さずに、以前配信していたものへ戻します。数十秒で終わります。

決めておくのは順番です。まず戻す。原因を調べるのはそのあと

原因を調べてから直そうとすると、調べている間ずっと壊れたままになります。戻してしまえば、平常の状態で落ち着いて調べられます。第7回で git revert を扱ったときと同じ考え方で、打ち消しは修正より先に来ます。

複数のサイトを1つのドメインに並べる

最後に、実際に運用している設定を1つ紹介します。BenriWorks では、企業サイトとブログが別々のリポジトリにあり、別々に配信されています。ただ、利用者から見えるのは1つのドメインです。

企業サイト側の設定で、特定のパスへの要求をブログ側へ回しています。

{
  "rewrites": [
    { "source": "/blog", "destination": "https://blog.benriwork.jp/blog/" },
    { "source": "/blog/:path(.*)", "destination": "https://blog.benriwork.jp/blog/:path" }
  ]
}

こうすると、benriwork.jp/blog/ を開いた人にはブログが表示されますが、URLは企業サイトのドメインのままです。リポジトリを分けたまま、見た目を1つにまとめられます。

この構成には、揃えておかないと壊れる設定があります。末尾のスラッシュの扱いです。実際に踏んだので、ブログ側の設定ファイルには理由をコメントとして残してあります。

benriwork.jp 全体が trailingSlash: true のため揃える。
揃えないと配信層(/blog/foo → /blog/foo/)とアプリ(/blog/foo/ → /blog/foo)で
互いに308し合い、リダイレクトループになる。

両側が相手と逆向きの転送を返し続けて、ページが永久に開かなくなります。設定を決めた理由を、設定の横に書いておく。半年後に片方だけ変更しようとした自分を止められます。

ここまでで通った道

第1回から15回かけて、1本の線がつながりました。

手元で Codex を動かし、規約と手順を渡し、Git で管理し、GitHub で確認し、自動検査を通し、Vercel で公開する。途中に止まる場所が3つあります。差分を読むところ、プルリクエスト、そして本番へ出す判断です。

3つとも、速さを落とす仕掛けです。AIが書く速さに人の判断が追いつかなくなるのを防ぐために、わざと置いています。

次の回

線はつながりましたが、実際にはあちこちで詰まります。第16回では、つまずきやすい場面を集めて、それぞれの切り分け方を書きます。

参照した情報

  • Vercel のデプロイ、環境変数、設定ファイルに関する公式ドキュメント(vercel.com/docs)
  • 引用した設定は BenriWorks の企業サイトとブログのリポジトリで実際に動いているもの

よくある質問

デプロイのたびに操作が必要ですか
必要ありません。GitHub と連携させると、反映のたびに自動でビルドと配信が走ります。本番用ブランチへの反映は本番として、それ以外のブランチは確認用として、別々のURLに出ます。
確認用URLが検索結果に出てしまいませんか
設定で防げます。自動で割り当てられるドメインからの応答にだけ、検索避けの応答ヘッダを付ける書き方があります。本番のドメインには付かないので、公開してよいものだけが索引に入ります。
本番で問題が見つかったらどうしますか
過去のデプロイへ戻せます。ビルドをやり直さずに、以前配信していたものへ切り替える操作です。原因を調べる前に、まず戻して平常に復帰させる。この順番を先に決めておくと、慌てずに済みます。

こんな記事も読まれています