企業サイトテンプレートをNext.js 15で作った
企業向けのWebサイトを案件ごとに毎回ゼロから作るのは非効率なので、使い回せるテンプレートを作った。
デモ: https://mochibullet.github.io/corporate-website-template/
技術スタック
- Next.js 15 (App Router) + React 18 + TypeScript 5
- Tailwind CSS v4 (CSS変数ベースのデザイントークン)
- Noto Sans JP (next/font/google)
- 静的出力 (
output: "export") - Vitest + React Testing Library
- AWS (S3 + CloudFront + Lambda) — IaCテンプレート付き
機能一覧
ページ構成
- トップ(ヒーロー + Stats + サービス + 最新お知らせ + CTA)
- 会社概要 / サービス / ニュース(一覧+詳細+ページネーション)
- お問い合わせフォーム / プライバシーポリシー / FAQ
- 採用情報 / 料金プラン(3プラン比較) / 導入事例 / 404
画像リソース
- Unsplash License(商用可)の画像 17枚 を同梱
- ヒーロー画像(トップ + 全サブページ)、サービス画像4枚、事例画像3枚
- PageHero共通コンポーネント — 画像+暗グラデーション+白テキストで全ページ統一
SEO・解析
- OGP / Twitter Card / metadataBase
- sitemap.ts / robots.ts の動的生成
- opengraph-image.tsx (Satori) でOGP画像を動的生成
- Google Analytics 4 (環境変数で切替)
運用面
site.config.tsで会社名・ロゴ・メニュー・沿革など 1箇所で全体設定管理- お問い合わせは Web3Forms / Lambda API の自動切替
scripts/create-client-site.shで顧客サイトを自動生成- GitHub Actions で S3デプロイ / GitHub Pagesデモデプロイ
数字で見る進捗
| 指標 | Before | After |
|---|---|---|
| Open Issue | 25件 | 4件 (AWS系3 + CMS検討1) |
| Merged PR | 0件 | 20件 |
| デモサイト | なし | GitHub Pages 画像付きで公開中 |
設計判断
設定の外部化
企業サイトで案件ごとに変わる部分(社名、ロゴ、メニュー構成、沿革、連絡先…)を全て src/site.config.ts に集約した。
site.config.ts を1ファイル書き換えるだけで
→ ヘッダー、フッター、会社概要、OGP、全部切り替わる
これで新規案件のセットアップが数分で終わる。
静的出力 + サブディレクトリ配信
output: "export" で静的HTMLを生成するので、どこにでもホストできる。
GitHub PagesではサブディレクトリURL(/corporate-website-template/)になるため、NEXT_PUBLIC_BASE_PATH 環境変数で basePath / assetPrefix を切り替える仕組みにした。
お問い合わせの二段構え
CONTACT_API_URL が設定されていれば → Lambda API
なければ WEB3FORMS_KEY で → Web3Forms
どちらもなければ → エラー表示
デモではWeb3Forms、本番案件ではLambdaに切り替える想定。
トップページの構成
Hero(画像+グラデーション)
→ Stats(4つの数字)
→ Services(3カード)
→ 最新のお知らせ(4件)
→ CTA(ご相談ください)
最新お知らせセクションを追加してサービスとCTAの間を埋めた。ニュースデータから自動取得。
ハマったところ
basePath + next/image の画像404問題(最大のハマりポイント)
next/image は images.unoptimized: true の時、srcにbasePathを自動付与しない。
GitHub Pagesのサブディレクトリ配信(/corporate-website-template/)で全画像が404になった。
→ 対策: site.config.ts に asset() ヘルパーを追加して全画像パスにbasePathを明示付与:
const BASE_PATH = process.env.NEXT_PUBLIC_BASE_PATH || "";
const asset = (path) =>
path && path.startsWith("/") ? `${BASE_PATH}${path}` : path;
// 利用例
logo: { src: asset("/logo.svg") }
heroImage: asset("/hero.jpg")
CSS/JS/フォントは assetPrefix で自動的にbasePathが付くが、画像のsrcだけは手動。新しい画像を追加する際も必ず asset() を経由させるルールにした。
output: "export" + OGP画像生成
opengraph-image.tsx で runtime = "edge" を指定すると静的エクスポートでエラーになる。
代わりに export const dynamic = "force-static" を使う必要があった。
GitHub OAuth の workflow スコープ
.github/workflows/ を含むファイルをpushするには workflow スコープが必要。
Termuxとproot(Ubuntu)で gh のconfig ファイルが別なのでトークン同期も必要だった。
News ページネーション
静的出力ではクエリパラメータ(?page=2)が使えない。
/news/page/[page]/page.tsx + generateStaticParams でビルド時に全ページを事前生成する方式にした。
残り4件
| 内容 | 必要な作業 |
|---|---|
| Route53 独自ドメイン | ドメイン購入 + Hosted Zone作成 |
| ACM証明書 (HTTPS) | us-east-1で発行 + DNS検証 |
| prod/staging環境分離 | AWSスタック2系統化 |
| CMS連携 | MDX + Decap CMS or microCMS 検討中 |
AWS系は実案件が入ったタイミングで対応。CMS連携は後日検討。 コード側のスケルトンはIaCに組み込める状態。
PR一覧(20件)
基盤整備・ページ追加・ニュース機能・SEO・GA4・テスト・Lighthouse最適化・画像リソース・Lambda API・GitHub Pages対応・basePath修正・トップページ改善まで、一通りのPRを積み上げた。
良かった点
site.config.ts への集約が効いた
案件ごとに変わる部分を1ファイルに寄せたおかげで、ナビゲーションにSNSアイコンを追加するとか、会社情報を差し替えるような作業がファイル横断の探し物にならない。テンプレートとして使う時の精神的コストが一気に下がった。
画像付きデモの破壊力
Unsplashで統一感のある画像を17枚選んで同梱したのは正解だった。「文字だけのデモ」と「写真入りのデモ」では、案件提案時の受け取られ方が明らかに違う。PageHero を共通コンポーネントにして全サブページで同じトーンに揃えたのも効いている。
小さくPRを刻めた
20件のPRは、どれも1〜数ファイルで閉じる粒度。後から履歴を追いやすく、「何がいつ入ったか」が git log で読める。ブランチ戦略というより、一息に書ききれるサイズで切るのを意識した結果。
静的出力の取り回しの良さ
output: "export" で吐いたHTMLは S3・GitHub Pages・どこでも配信できる。デモをGitHub Pagesに、本番をS3+CloudFrontに、という運用が同じビルド成果物で成立する。
反省点
basePath問題を詰めきる前にデモを公開しかけた
next/image が unoptimized: true のとき basePath を自動付与しない挙動を知らず、デモ公開直前に全画像404で焦った。事前に next/image のドキュメントと assetPrefix の挙動を読み込んでおけば避けられたミス。asset() ヘルパーという形で解消したが、新しい画像を追加するたびに asset() を通すという運用ルールが必要になってしまった。自動化したい。
余白設計を後回しにした
最初は機能追加優先で余白をあまり考えず進めたため、完成後に「全体的に窮屈」という印象になって全ページの padding / margin / line-height を一斉に広げる手戻りが発生した。デザイントークンに縦方向のスペーシングスケールを先に決めておけば、この手戻りは不要だった。
ダークモードの検証不足
prefers-color-scheme: dark のCSS変数は定義したものの、各ページで実際にダーク環境に切り替えて見る検証まで回せていない。OGP画像やヒーローの暗オーバーレイとの相性はちゃんと確認したい。
AWS系を後回しにしすぎた
Route53 + ACM + prod/staging分離は「実案件が来たら」と棚上げした。とはいえ実案件が来た時にゼロから触るのはリスクなので、ダミードメインで一度通しておくくらいはしておけばよかった。
CMS連携の判断を先送りした
MDX(自前) / Decap CMS / microCMS で迷ったまま未決着。記事更新を非エンジニアに任せるかどうかで選択肢が変わる部分なので、案件要件が固まる前に自分なりの推奨を決めておくのが本来の姿。
画像の出典管理が属人的
Unsplashライセンスは商用OKだが、どの画像がどのURLから来たかを管理するファイルを作らなかった。将来の差し替えやクレジット表記で困りそう。content/image-credits.json のようなメタデータを後から足すべき。
まとめ
「テンプレート」と言いつつ、SEO・解析・画像・デプロイ・テストまで一通り揃えた。
特に画像付きのデモサイトが公開できたことで、案件提案時の説得力が格段に上がった。
次の企業サイト案件ではこれをフォークして site.config.ts を書き換えるだけで始められる。