はじめに
Web開発では、些細な問題が大きな発見につながることがあります。今回は、SPAルーティング問題の解決に向けて試行錯誤した過程を振り返り、失敗から学んだことを整理してみます。
前回の記事で触れた「解決策1」がなぜ失敗したのか、その理由と最終的な解決策に至るまでのトラブルシューティングの全過程を時系列で整理します。
トラブルシューティングの開始:HTML拡張子の削除
最初に試した解決策
Next.jsでSSGした静的サイトをS3でホスティングする際のCSR後リロード時404問題の解決という記事において、Next.jsのnext export
で生成されるportfolio.html
やabout.html
などのファイルを、URLで.html
なしでアクセスできるよう、拡張子なしのファイルに変換する手法が提案されていました。
この手法では追加のインフラリソースを必要とせず、GitHub Actionsのワークフロー内での処理を修正するだけで解決できそうだったので、CloudFront Functionsより先に一番最初に試してみました。
実装したアプローチ
GitHub Actionsのワークフロー内で、HTMLファイルの拡張子を削除する処理を実装しました:
# Process HTML files for SPA routing
- name: Process HTML files for SPA routing
working-directory: frontend
run: |
# Remove unnecessary files
find ./out -name ".DS_Store" -delete
find ./out -name ".keep" -delete
# Store original HTML file paths before renaming
html_files=$(find ./out -name "*.html" ! -path "*/index.html" ! -path "*/_next/*" ! -path "*/node_modules/*" ! -path "*/\.*")
if [ -n "$html_files" ]; then
# Store the list for later use in Content-Type setting
echo "$html_files" > /tmp/html_files_list.txt
# HTML file extension removal
for file in $html_files; do
new_name="${file%.html}"
mv "$file" "$new_name"
done
else
touch /tmp/html_files_list.txt
fi
また、拡張子なしのファイルに変換した後、S3にアップロードする際にContent-Typeをtext/html
に設定する処理も含めていました。これにより、拡張子なしのファイルでもブラウザがHTMLとして正しく認識できるようになります。
予想外の問題発生:ファイル名とディレクトリ名の衝突
問題の発見
HTML拡張子の削除を試みた際に、予想外の問題が発生しました。それは拡張子なしのportfolioとlifeのファイルが作成されず、それぞれのディレクトリ配下にhtmlファイルが作成されるという問題でした。
問題の詳細
理想的な構成:
./out/
├── portfolio/ # 既存のディレクトリ
├── life/ # 既存のディレクトリ
├── portfolio # 拡張子なしのファイル
├── about # 拡張子なしのファイル
├── life # 拡張子なしのファイル
└── contact # 拡張子なしのファイル
実際の構成:
./out/
├── portfolio/
│ ├── 2024-0629.md
│ └── portfolio.html # ディレクトリ配下に作成されてしまう
├── life/
│ ├── 2025-0720.md
│ └── life.html # ディレクトリ配下に作成されてしまう
├── about.html
└── contact.html
なぜこうなるのか
portfolio
、life
という名前のディレクトリが既に存在- GitHub Actionsで利用されているUbuntuOSでは、同じ階層に同じ名前のファイルとディレクトリを共存できない
- ワークフロー内の処理で既存ディレクトリ配下に格納されてしまう
最終的な解決策:CloudFront Functionsによる根本的解決
ここまでくると、HTMLファイルの拡張子を削除する手法での解決は難しそうです。というわけで、CloudFront Functionsによって解決することになりました。
詳細な実装方法については、以前の記事で詳しく解説しています。
失敗から学んだこと:GitHub Actionsの最適化
シンプル化されたワークフロー
CloudFront Functionsによる解決策が確立されたことで、GitHub Actionsの役割が明確になり、HTML拡張子の削除という複雑な処理が不要になりました。
現在のワークフロー:
# シンプル化されたファイル処理
- name: Process HTML files for SPA routing
working-directory: frontend
run: |
echo "Processing HTML files for SPA routing..."
# Remove unnecessary files only
find ./out -name ".DS_Store" -delete
find ./out -name ".keep" -delete
echo "SPA routing optimization applied"
改善されたポイント
- HTML拡張子削除の削除: 複雑なファイル処理ロジックを削除
- Content-Type設定の削除: S3でのContent-Type設定処理も不要に
- シンプルな構造: 必要最小限の処理のみ実行
- 保守性の向上: ファイル構造に依存しない設計
- エラーリスクの削減: ファイル名とディレクトリ名の衝突による失敗が発生しない
トラブルシューティングから学んだこと
1. 技術選定の重要性
問題の性質に応じて、適切な技術を選択することが重要です。今回の場合は、GitHub ActionsでのHTML拡張子の削除よりもCDNレベルでのURLリライトが適していました。
2. 解決手法の使い分け
GitHub ActionsでのHTML拡張子の削除による解決は、追加のインフラリソースを必要としない利点がありますが、ファイルシステムの制約により実現が困難でした。一方、CloudFront Functionsによる解決は、インフラレベルでの柔軟性を提供し、より確実にSPAルーティングを実現できます。状況に応じて適切な手法を選択することが重要です。
3. CI/CDでの適切な役割分担
CI/CDパイプラインでは、複雑なファイル処理よりも、シンプルで確実な処理に集中することが重要です。
まとめ
GitHub Actionsのワークフロー内でのHTML拡張子削除から始まり、ファイル名とディレクトリ名の衝突という根本的な問題に気づき、最終的にCloudFront FunctionsによるURLリライトに至った今回のトラブルシューティングは、Web開発における問題解決の典型的なパターンを示しています。
失敗から学んだことで、より適切な技術選定とCI/CDの役割分担ができ、最終的にはCloudFront Functionsによる解決により、ユーザーはどのページからでも安全にページを更新できるようになり、サイトの使いやすさが大幅に向上しました。
関連記事:
参考資料: