はじめに
GitHub Actionsでビルドとデプロイを自動化するワークフローを実行したら、「distディレクトリが存在しない」という内容のエラーが出たのでその解決方法をまとめます。
エラーの原因
=== Deploying to '***'...
i deploying hosting
i hosting[***]: beginning deploy...
Error: Directory 'dist' for Hosting does not exist.
Error: Process completed with exit code 1.
このエラーは、Firebase Hostingへのデプロイ時に、参照しようとしたdistディレクトリがGitHub Actionsのランナー(仮想マシン)上に存在しないと発生します。
状況としては、ビルドとデプロイのジョブは分けていて、ビルドのジョブは成功していましたがデプロイの処理でエラーが出ていました。
エラーが出たデプロイのジョブは以下のコードです。(長いので一部省略してます)
jobs:
deploy:
name: deploy
runs-on: ubuntu-latest
needs: build
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Setup Node.js and cache
uses: actions/setup-node@v7
with:
node-version-file: "package.json"
cache: "npm"
- name: Install firebase-tools
run: npm install --save-dev firebase-tools
- name: Decode Firebase service account key
run: |
echo "${{ secrets.FIREBASE_KEY }}" | base64 -d > ./firebase-key.json
echo "GOOGLE_APPLICATION_CREDENTIALS=${{ github.workspace }}/firebase-key.json" >> $GITHUB_ENV
- name: change space
run: ./node_modules/.bin/firebase use ${{ secrets.FIREBASE_PROJECT_ID }}
- name: Deploy to Firebase Hosting
run: |
./node_modules/.bin/firebase deploy
env:
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
FIREBASE_CLI_EXPERIMENTS: webframeworks
- name: delete GOOGLE_APPLICATION_CREDENTIALS
run: rm $GOOGLE_APPLICATION_CREDENTIALS
if: ${{ always() }}
調べて分かったのが、GitHub Actionsはジョブ間でファイルを共有していません。そのため、ビルドのジョブが実行されてdistディレクトリが生成されてもデプロイのジョブへ引き継がれません。
ランナー上にdistディレクトリが存在していると思っていましたが、実際はビルドのジョブが終了した時点で破棄されていたのでデプロイのジョブでエラーが出ていました。
解決方法
単純な解決策として、デプロイのジョブでもビルドを実行すれば生成されるdistディレクトリをそのまま利用出来ます。
jobs:
deploy:
name: deploy
runs-on: ubuntu-latest
needs: build
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Setup Node.js and cache
uses: actions/setup-node@v7
with:
node-version-file: "package.json"
cache: "npm"
- name: Run build # ビルドを追加
run: npm run build
# 以下省略
ただ、これだとジョブが違うとはいえ同じことを2回やってしまっているのとビルドのジョブの意味が無くなります。あと何かスマートじゃない。
異なるジョブ間でファイルを受け渡す方法がないか探したら見つかりました。
Artifact
Artifact(アーティファクト)は、GitHub Actionsのワークフローにおいて、ジョブの実行によって生成されるファイルやディレクトリを保存し、他のジョブで再利用するための機能です。ビルドの成果物、テスト結果のレポート、ログファイルなど、様々な種類のファイルをアーティファクトとして保存することができます。
アーティファクトを使用することで、異なるジョブ間でファイルを共有することができます。たとえば、ビルドジョブで生成したアプリケーションのバイナリファイルを、テストジョブやデプロイジョブで使用するといった利用方法が可能です。
Artifactのアップロード
ビルドのジョブでdistディレクトリをArtifactへアップロードします。
name: Firebase deploy
on:
push:
workflow_dispatch:
jobs:
build: # ビルドのジョブ
name: build
runs-on: ubuntu-latest
env:
VITE_SUPABASE_URL: ${{ secrets.VITE_SUPABASE_URL }}
VITE_SUPABASE_PUBLISHABLE_KEY: ${{ secrets.VITE_SUPABASE_PUBLISHABLE_KEY }}
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Setup Node.js
uses: actions/setup-node@v7
with:
node-version-file: "package.json"
- name: Install dependencies
run: npm install
- name: Run build
run: npm run build
- name: Upload build-artifacts # 追加
uses: actions/upload-artifact@v7 # 追加
with: # 追加
name: build-artifacts # 追加
path: dist # 追加
追加したactions/upload-artifactでArtifactにアップロードしています。
- name: Upload build-artifacts
uses: actions/upload-artifact@v7
with:
name: build-artifacts
path: dist
with以下にあるnameはGitHub Actions上で識別するArtifact名です。省略するとartifactになります。pathにはArtifactにアップロードするファイルのパスを書きます。
イメージとしては以下のようにArtifactにアップロードされます。(ファイル名は例です)
build-artifacts
├── index.html
├── assets/
│ ├── index.js
│ └── style.css
└── favicon.ico
Artifactにアップロードしたファイルはジョブからだけでなく、GitHubのワークフローの履歴からもダウンロード出来るようになります。
リポジトリの権限にもよりますが、Artifactにアップロードしたファイルを第三者がダウンロード出来てしまうため、秘密鍵やAPIキーのような秘密情報はArtifactにアップロードしてはいけません。
Artifactからダウンロード
ビルドのジョブでArtifactへアップロードしたファイルをデプロイのジョブでダウンロードします。
deploy: # デプロイのジョブ
name: deploy
runs-on: ubuntu-latest
needs: build
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Setup Node.js and cache
uses: actions/setup-node@v7
with:
node-version-file: "package.json"
cache: "npm"
- name: Download build artifacts # 追加
uses: actions/download-artifact@v7 # 追加
with: # 追加
name: build-artifacts # 追加
path: dist # 追加
# 以下変更が無いので省略
actions/download-artifactはArtifactにアップロードされたファイルをダウンロードします。nameにはダウンロードしたいArtifact名を指定し、pathにはダウンロード先のパス名を書きます。
- name: Download build artifacts
uses: actions/download-artifact@v7
with:
name: build-artifacts
path: dist
イメージとしては以下のようにArtifactからダウンロードされます。
プロジェクト/
└── dist/
├── index.html
├── assets/
│ ├── index.js
│ └── style.css
└── favicon.ico
Artifactを追記した全体のコードは以下になります。
name: Firebase deploy
on:
push:
workflow_dispatch:
jobs:
build: # ビルド時の処理
name: build
runs-on: ubuntu-latest
env:
VITE_SUPABASE_URL: ${{ secrets.VITE_SUPABASE_URL }}
VITE_SUPABASE_PUBLISHABLE_KEY: ${{ secrets.VITE_SUPABASE_PUBLISHABLE_KEY }}
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Setup Node.js
uses: actions/setup-node@v7
with:
node-version-file: "package.json"
- name: Install dependencies
run: npm install
- name: Run build
run: npm run build
- name: Upload build-artifacts
uses: actions/upload-artifact@v7
with:
name: build-artifacts
path: dist
deploy: #デプロイ時の処理
name: deploy
runs-on: ubuntu-latest
needs: build
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Setup Node.js and cache
uses: actions/setup-node@v7
with:
node-version-file: "package.json"
cache: "npm"
- name: Download build artifacts
uses: actions/download-artifact@v7
with:
name: build-artifacts
path: dist
- name: Install firebase-tools
run: npm install --save-dev firebase-tools
- name: Decode Firebase service account key
run: |
echo "${{ secrets.FIREBASE_KEY }}" | base64 -d > ./firebase-key.json
echo "GOOGLE_APPLICATION_CREDENTIALS=${{ github.workspace }}/firebase-key.json" >> $GITHUB_ENV
- name: change space
run: ./node_modules/.bin/firebase use ${{ secrets.FIREBASE_PROJECT_ID }}
- name: Deploy to Firebase Hosting
run: |
./node_modules/.bin/firebase deploy
env:
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
FIREBASE_CLI_EXPERIMENTS: webframeworks
- name: delete GOOGLE_APPLICATION_CREDENTIALS
run: rm $GOOGLE_APPLICATION_CREDENTIALS
if: ${{ always() }}
実際に実行されているのがランナーなのでイマイチ分かりにくいですが、処理の流れはワークフローの履歴に表示されているのでこれを1つ1つ追っていくと何をやっているか分かってきます。
おわりに
今回は同一のワークフロー間でArtifactを利用しましたが、異なるワークフローにもArtifactを経由してファイルの受け渡しが出来るみたいです。Artifactを色々なパターンを試してもっと理解を深めていきたいです。
参考



