はじめに
自分の作品や経歴をまとめるポートフォリオサイトを、Next.js・microCMS・Vercel で作って、独自ドメインで公開しました。
この記事では、サイトを作る中で使った技術や、どんな流れで進めたか、どこでつまずいたかを中心に振り返ってみます。
技術構成
使ったものはこんな感じです。
| 役割 | 使ったもの |
|---|---|
| フレームワーク | Next.js(App Router)、React、TypeScript |
| コンテンツ管理 | microCMS(microcms-js-sdk) |
| ホスティング | Vercel(Hobby プラン) |
| ソース管理 | GitHub |
| フォント | Adobe Fonts、Google Fonts |
| 素材制作 | Illustrator |
| 開発環境 | VS Code |
| AI ツール | Claude(相談・指示の設計)、Claude Code(実装) |
| ドメイン | 独自ドメイン(.jp) |
アニメーションは CSS・SVG・Canvas だけで作っていて、アニメーション用のライブラリは入れていません。
制作の進め方(AI との役割分担)
実装の多くは Claude Code にお願いしました。その分、自分は「何を作りたいか」と「それをどう伝えるか」を考えることに時間を使っています。
AIの使い方は以下の通りです。
- Claude(チャット) では、やりたいことを相談しながら、Claude Code に渡す指示を一緒に組み立てました
- Claude Code(VS Code) には、その指示を渡して実装してもらい、ビルドや表示の確認までやってもらいました
- Claude(ブラウザ操作) には、microCMS や Vercel の管理画面の設定を代わりに操作してもらいました。ログインや支払いのように自分でやるべき場面では、ちゃんと止まってもらうようにしています
指示を書くときに気をつけたこと
何度かやり取りする中で、指示の書き方で結果がかなり変わることに気づきました。意識していたのは次のようなことです。
- 「既存のレイアウトは変えない」のように、触ってほしくないところをはっきり書く
- いきなり実装させずに、先に変更する内容の一覧を出してもらう。ズレていたらそこで止められます
- 動きや大きさは「0.3秒」「最大2000px」みたいに、数字で伝える
- 色や時間、サイズは CSS 変数や定数にまとめてもらって、あとから自分でも調整しやすくする
- API キーはチャットに貼らず、
.env.localに自分で書き込む
実際に渡した指示の一部を載せておきます。
# 作業前に確認すること
- 現在の作品データの持ち方と、一覧・詳細ページの実装を確認する
- 実装方針を提示し、確認を取ってから実装する
# 守ること
- 既存のデザイン・レイアウトは変えない
- API キーはサーバー側でのみ使う(NEXT_PUBLIC_ は付けない)
- 閲覧のたびに API を呼ばない静的ページにする
レイアウトとアニメーション
レイアウトは画像ではなく CSS で組む
最初は「Illustrator で作った画面を画像で貼れば、崩れにくいんじゃないか」と思っていました。でも実際は逆で、画像だとスマホでそのまま縮小されてしまい、文字が読めなくなります。結局、文字とレイアウトは HTML/CSS で組んで、装飾だけを SVG にする形に落ち着きました。
一覧は grid で並べていて、画面の幅に合わせて列の数が自動で変わるようにしています。
.works {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 24px;
}
途中で配色をガラッと変えたことがあったのですが、色があちこちに直接書かれていて、直すのがかなり大変でした。それからは、色・余白・文字サイズを全部 CSS 変数にまとめるようにしています。
スクロールに合わせた演出
装飾は IntersectionObserver を使って、セクションが画面に入ったタイミングで表示しています。
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("is-visible");
observer.unobserve(entry.target); // 一度出したら監視をやめる
}
});
});
動きをつけるときに気をつけたのは、このあたりです。
- 動かすのは
transformとopacityだけにして、レイアウトの再計算が起きないようにしました - 画面を覆った色を少しずつ消して、下のページを見せる演出は、Canvas の
globalCompositeOperation = "destination-out"で穴を空けていく方法で作りました - OS で「視差効果を減らす」を設定している人には、動きを止めるようにしています
@media (prefers-reduced-motion: reduce) {
* { animation: none !important; transition: none !important; }
}
GitHub + Vercel で公開
公開の手順はシンプルでした。
- VS Code のプロジェクトを GitHub に push する
- Vercel に GitHub アカウントでログインして、「Add New → Project」からリポジトリを選ぶ
- Application Preset が「Next.js」になっているのを確認して、Deploy を押す
あとは main ブランチに push するたびに、自動でデプロイされます。もしビルドに失敗しても、Vercel は前の正常な状態のまま公開を続けてくれるので、本番が壊れる心配はありません。これはかなり安心でした。
microCMS でコンテンツを管理
最初は作品のデータをコードの中のファイルで持っていたのですが、作品を追加するたびに push しないといけないのが面倒で、microCMS に移しました。今はスマホやパソコンから管理画面で「公開」を押すだけで、1分くらいで本番に反映されます。
microCMS にデータを取りに行くのは、ビルドのときだけです。見に来た人には作り置きのページを返すので表示が速く、microCMS の転送量もほとんど使いません。
microCMS 側でやったこと
- リスト形式の API を作りました(作品用の
worksと、経歴用のcareer) - フィールドを作りました。作品なら slug・title・thumbnail(画像)・category(セレクト)・tools(複数選択)・description(リッチエディタ)・images(複数画像)などです
- 読み取り専用(GET だけ)の API キーを用意しました
Next.js 側でやったこと
接続情報は .env.local に書いて、.gitignore で GitHub に上がらないようにしています。Vercel にも同じ値を環境変数として登録しました。
MICROCMS_SERVICE_DOMAIN=サービスID
MICROCMS_API_KEY=読み取り専用のAPIキー
microCMS とつなぐ部分は1つのファイルにまとめて、server-only を使ってブラウザ側からは読み込めないようにしました。環境変数が入っていないときは、ビルドがエラーで止まるようにしています。
import "server-only";
import { createClient } from "microcms-js-sdk";
if (!process.env.MICROCMS_SERVICE_DOMAIN || !process.env.MICROCMS_API_KEY) {
throw new Error("microCMS の環境変数が設定されていません");
}
export const client = createClient({
serviceDomain: process.env.MICROCMS_SERVICE_DOMAIN,
apiKey: process.env.MICROCMS_API_KEY,
});
作品の詳細ページ /work/[slug] は、generateStaticParams を使ってビルドのときに全部作っておきます。
export const dynamicParams = false;
export async function generateStaticParams() {
const works = await getWorks();
return works.map((work) => ({ slug: work.slug }));
}
ちゃんと静的に作れているかは、npm run build の最後に出てくる記号で確認できます。
○ (Static) 作り置きのページ
● (SSG) データから作り置きしたページ
ƒ (Dynamic) 閲覧のたびに作るページ
/work/[slug] が ● になっていれば、狙いどおりです。
画像
microCMS の画像は、URL にパラメータを付けるだけでサイズや形式を変えて配信できます。今は、一覧では幅 384px、詳細では 1080px の WebP で出しています。next/image で使うために、next.config.ts の remotePatterns に images.microcms-assets.io を追加しました。アップロードする前にも、WebP にして横幅 2000px 以内に収めるようにしています。
公開したら自動で再ビルドされるようにする
microCMS で公開しただけでは、そのままだとサイトに反映されません。そこで、公開をきっかけに Vercel がビルドし直すように設定しました。
- Vercel の Settings → Git → Deploy Hooks で、main ブランチ用の URL を作る
- microCMS の API 設定 → Webhook に、その URL を登録する
- 通知のタイミングは「公開・更新」「公開終了」「削除」にする
ひとつハマりかけたのが、Webhook は API ごとに設定が必要だということです。経歴用の API を後から追加したときに、そちらにも登録しないといけませんでした。それと、Deploy Hook の URL は知っている人なら誰でもビルドを動かせてしまうので、人に見せないように気をつけています。
独自ドメイン
ドメインの設定は、次の流れで進めました。
- ドメインを購入する
- Vercel の Settings → Domains でドメインを追加する
- Vercel に表示された DNS レコードを、購入先の DNS 設定に入力する
-
www.付きも追加して、www なしに転送されるようにする - 環境変数
NEXT_PUBLIC_SITE_URLに新しいドメインを設定して、再デプロイする
学んだこと
作ってみて、特に大事だなと感じたことが3つあります。
ひとつ目は、見た目と中身を分けておくと、変更にすごく強くなるということです。デザインはコード、コンテンツは microCMS と分けていたおかげで、途中でデザインを大きく変えても、データには何の影響もありませんでした。
ふたつ目は、AI には「やってほしいこと」だけでなく「変えないもの」と「確認のタイミング」も伝えることです。触ってほしくない範囲と、実装する前に方針を見せてほしいことを書くようにしてから、やり直しがぐっと減りました。
みっつ目は、重さは最初から気にしておくことです。静的生成、WebP、transform と opacity だけのアニメーションを意識していたので、演出をたくさん入れても軽く動いてくれました。
おわりに
Next.js・microCMS・Vercel を組み合わせることで、デザインは自由に作り込みつつ、中身は管理画面から気軽に更新できる構成を、無料枠の範囲で運用できています。
費用はほぼドメイン代だけで済みますし、作品が増えるたびにスマホから追加できるので、就職活動やイベントの前にも慌てずに更新できます。何より、自分でサイトを作って公開するまでの経験そのものが、ひとつの作品になるので、同じような構成を考えている人、特に学生の方の参考になればうれしいです。