GitHub Pagesでフロントエンド開発のステージング環境を手軽に構築する(翻訳)
はじめに
ステージング(staging)環境のセットアップは、Web開発プロセスにおいて重要な部分であり、開発者は「新機能のお試し」「共同作業」「ランスルーテスト」「バグ修正」をここで行います。ステージング環境の構築方法はさまざまですが、本記事では、予算が限られている小規模プロジェクトを対象にして、財布に優しいステージング環境のセットアップ方法を解説します。他にも、プルリクを別のWebドメインにデプロイするなどの実用的な方法についても解説します。
フロントエンド開発用のステージング環境は、多種多様な選択肢の中から選んで実装できます。
Webアプリケーションをボタン1つでデプロイできるVercelやNotifyなどのホスティングサービスを使う方法もその1つですが、このオプションを利用できるのは、自分たちがホスティングサービスの顧客である場合だけです。
そうしたホスティングサービスでアプリケーションをホスティングしていないのであれば、AWSやGoogle CloudやHerokuなどのクラウドサービスでステージング環境を構築する方法もあります。こちらの方が柔軟性に優れているものの、場合によってはかなりの専門知識とカスタマイズの労力を必要とします。
しかし、追加費用を出す余裕のない小規模プロジェクト用にステージング環境を手軽に実装する方法は他にもいくつかあります。本記事ではその中から、GitHub Pagesを用いてプロジェクトのフロントエンド部分のstagingブランチを簡単に作成する方法を検討することにします。この方法では、stagingブランチをmainブランチにマージするときに、ブランチでの変更や削除を自動的に伝播させるプロセスも含まれます。これにより、プロジェクトへの変更内容と、変更したユーザーを明確に把握できるようになります。なお私は個人的にStorybookをこの種の目的に利用していますが、皆さんの好みのツールを自由に利用できます。
🔗 基本部分のセットアップ
最初に、プロジェクトで空のブランチを1つ作成します。これからこのブランチで魔法が行われます。作成したら、GitHubのリポジトリ設定ページを開き、サイドメニューの[Settings]でGitHub Pagesをそのブランチに対して有効にします。なお、私の場合はstorybook-pages
というブランチにしています。
作成したブランチでGitHub Pagesを有効にした様子
なお、カスタムドメインが必要な場合は以下のガイドを利用できます。
参考: GitHub Pages サイトのカスタムドメインを設定する - GitHub Docs
次のステップでは、プロジェクトのrootディレクトリに.github
フォルダを作成し、さらに.github
フォルダの下に workflows
フォルダも作成します。この後で、 workflows
フォルダの中にGitHub Actions用のファイルを2つ追加する必要があります。ファイル1はデプロイ用、ファイル2はブランチ削除用です。
GitHub上の環境を正常に削除するには、GitHubのパーソナルアクセストークン(Personal Access Token)を取得しておく必要があります。このトークンを生成するには、GitHubサイトで自分のアカウントページを開き、サイドメニューの[Developer settings]をクリックします。表示されたページで、サイドメニューの[Personal Access Tokens]を展開して[Fine-grained personal access tokens]を選択し、パーソナルアクセストークンを作成します。
"fine-grained"トークン
新規トークンを生成するときには、有効期間を指定しておくことが重要です(作成日から最長で1年)。さらに、このトークンに付与する権限も指定しなければなりません。ステージング環境を削除するには、[Read access to metadata](メタデータの読み取り)パーミッションに加えて[Read and Write access to administration and deployment](管理とデプロイの読み取りと書き込み)パーミッションも必要です。また、トークンの作成中に、どのリポジトリで環境を削除するかを指定する必要もあります。
ヒント: トークンを作成するときに与える権限は最小限にとどめましょう。またデジタル衛生(digital hygiene)のためにも、トークンを複数のリポジトリで使い回さず、リポジトリごとにトークンを作成しましょう。
トークンのパーミッション
GitHub上の環境を削除するうえでは、パーソナルアクセストークンを取得しておくことが重要なステップである点にご注意ください。このトークンがなければ、環境を削除することも、デプロイを効率よく管理することもできません。上の手順に沿って新しいトークンを適切な権限で作成しておけば、環境を正常に削除してデプロイを合理化できるようになります。
作成が終わったら、作成したパーソナルアクセストークンをリポジトリの設定に追加する必要があります。リポジトリの[Settings]タブでサイドメニューの[Secrets and variables]を展開して[Actions]をクリックします。次に[New repository secret]ボタンをクリックして、[Name]フィールドに名前を入力し、[Secret]フィールドにトークンそのものを貼り付けます。入力する名前は後で必要になるので、どこかにメモしておきましょう。
トークンを追加する
ヒント: ビルド内のファイル名にアンダースコア_
が使われていると、デプロイ時にそれらのファイルにアクセスできない(=リクエスト時に404エラーが表示される)場合があります。その理由は、GitHub Pagesではアンダースコアを含むファイル名がサポートされていないからです(参考)。この問題を解決するには、GitHub Pagesのブランチのrootディレクトリに.nojekyll
ファイルを作成してからGitHubで実行する必要があります。これにより、GitHub PagesでJekyll固有の機能がバイパスされ、アンダースコアを含むファイル名をデプロイできるようになります。
🔗 ファイル1: ビルドとデプロイ用
.github/workflows/preview.yml
というファイルを作成します。GitHub Actionsで使う最初のファイルを見てみましょう。
name: Build and Deploy
on:
push:
pull_request:
types: [reopened]
permissions:
contents: write
pull-requests: write
deployments: write
env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
jobs:
build-and-deploy:
concurrency: ci-${{ github.ref }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Create deployment
uses: bobheadxi/deployments@v1
id: deployment
with:
step: start
token: ${{ secrets.GITHUB_TOKEN }}
env: staging-${{ env.BRANCH_NAME }}
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Building Storybook
run: |
yarn
STORYBOOK_BUILD_PATH=${{ env.BRANCH_NAME }} yarn run build-storybook
- name: Create a version mark
run: |
touch ./storybook-static/${{ github.sha }}.txt
- name: Pushing to pages branch
uses: JamesIves/github-pages-deploy-action@v4
with:
branch: storybook-pages
folder: storybook-static
target-folder: ${{ env.BRANCH_NAME }}
- name: Wait for GitHub Pages to be deployed
uses: mydea/action-wait-for-api@v1
with:
url: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/${{ env.BRANCH_NAME }}/${{ github.sha }}.txt
expected-status: 200
timeout: 600
interval: 15
- name: Update deployment status
uses: bobheadxi/deployments@v1
if: always()
with:
step: finish
token: ${{ secrets.GITHUB_TOKEN }}
status: ${{ job.status }}
env: ${{ steps.deployment.outputs.env }}
deployment_id: ${{ steps.deployment.outputs.deployment_id }}
env_url: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/${{ env.BRANCH_NAME }}
deploymentsというGitHub Actionのおかげで、プルリクのデプロイステータスを手軽に表示できます。[View deployment]ボタンをクリックすれば、プルリクのビルドをブラウザの別ウィンドウで開けます。
いくつかの仕様により、rootブランチのデプロイが完了するまでデプロイへのリンクは有効になりません。プルリクデプロイのステータスが正しいことを確認するために、Create a version tag
ステップを作成することにします。このステップでは、storybook-static
フォルダ内に、コミットのハッシュを名前に持つファイルを作成します。これにより、rootブランチがデプロイされるのを待ってから、プルリクにデプロイのステータスが表示されるようになります。
なお、Storybookを使わない場合は、Pushing to pages branch
ステップのfolder
で指定したフォルダ内に、コミットのハッシュを名前に持つファイルを作成する必要があります(つまりこれをビルドディレクトリのrootにする必要があります)。
"Deployment status"ページ
なお、env
フィールドやenv_url
フィールド内のリンクは自動生成されるので、変更は不要です。
ここで注目いただきたいのは、このリポジトリでは以下のようにすべてのアクティブな環境が表示されるので、環境の個数を管理することも、ビルドに素早くアクセスすることも可能になる点です。
アクティブな環境のリスト
この.github/workflows/preview.yml
ファイル内では、BRANCH_NAME
変数を使うことが重要です。この変数には、プルリクが行われたブランチ名を代入します。これは、後でプルリクがmainブランチにマージされるときにデプロイブランチを削除可能にするために必要となります。
また、github.head_ref
変数も必要です。
- (forkからではなく)このブランチからプルリクが行われると、プルリクが行われたブランチ名をこの変数に渡します。
- forkからプルリクが作成された場合は
github.head_ref
変数が使われ、プルリクを行ったブランチ名をこの変数に渡します。
これは、後でプルリクがmainブランチにマージされるときにデプロイブランチを削除可能にするために必要となります。
特定ファイルが変更された場合にのみデプロイブランチを作成したい場合は、.github/workflows/preview.yml
ファイルのon
セクションに以下のコードを追加します。
on:
push:
paths:
- 'root/path_to_file'
🔗 ファイル2: ブランチ削除用
2番目の.github/workflows/cleanup.yml
ファイルは、プルリクがmainブランチにマージされるときにデプロイブランチを削除する役割があります。
name: Cleanup Stale Pages
on:
pull_request:
types: [closed]
permissions:
contents: write
pull-requests: write
deployments: write
env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
jobs:
remove_stale_pages:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Create an empty dir
run: |
mkdir storybook-dummy
touch storybook-dummy/.gitkeep
- name: Pushing to pages branch
uses: JamesIves/github-pages-deploy-action@v4
with:
branch: storybook-pages
folder: storybook-dummy
target-folder: ${{ env.BRANCH_NAME }}
- name: Delete deployment
uses: bobheadxi/deployments@v1
if: always()
with:
step: delete-env
token: ${{ secrets.REMOVE_ENV_TOKEN }}
env: staging-${{ env.BRANCH_NAME }}
このファイルのtoken
フィールドには、GitHubリポジトリ設定の[Actions secrets and variables]セクションで追加したトークン名を指定する必要があります(トークン名をメモするよう指示したのを覚えていますか?)
このファイル2を使って、storybook-pages
ブランチに空のフォルダを1個作成し、プルリクを行ったブランチ名を使ってブランチにプッシュします。これにより、デプロイブランチが削除されます。
Storybookを正しいブランチでビルドするには、.storybook/main.js
ファイルで以下の変数を設定します。
const { STORYBOOK_BUILD_PATH } = process.env;
const REPO_NAME = 'YOUR_REPO_NAME';
リポジトリ名を含めるときの例
利用するコンフィグ(プロジェクトのコンフィグとStorybookのコンフィグ)に接続するメソッドでは、以下のようにViteConfigのメソッドを利用して以下のコードを書きます。
if (configType === 'PRODUCTION') {
config.base = `/${REPO_NAME}/${STORYBOOK_BUILD_PATH}`;
}
これにより、「プルリクが作成されたブランチ名」を名前に持つフォルダを作成するようStorybookに指示されます。
🔗 試してみる
すべての設定が完了したら、次のステップはプルリクを作成することです。新しいプルリクを作成するオプションを選択して、必要な情報を入力するだけで済みます。
プルリクが作成されると、ブランチのデプロイビルドへのリンクを含むコメントがそのプルリクに追加されていることがわかります。他の人がこのリンクを使って変更内容を確認したり、必要に応じてフィードバックしたりできます。
以上でおしまいです!このプロセスは全般的に、共同作業を効率化して、チームの全メンバーが最新の変更内容を確実に把握可能にするうえで有用です。
Evil Martiansは、成長段階のスタートアップ企業をユニコーン企業に飛躍させるためにサポートいたします。開発ツールの構築やオープンソース製品の開発も行っています。ワープの準備が整ったお客様、ぜひフォームまでご相談をお寄せください!
概要
元サイトの許諾を得て翻訳・公開いたします。
日本語タイトルは内容に即したものにしました。