概要
ECサイト(icoi-v4プロジェクト)をWordPressからAstro SSGに移行しました。28商品のコンテンツページをCSVから自動生成するパイプラインを構築し、Claude Codeで実装を進めた記録です。
ポイントは2つあります。1つ目はCSVからMDXへの自動生成パイプライン、2つ目は8-10件ずつのバッチ処理によるセッション管理です。
移行の全体像
Before(WordPress)
- WordPressの記事として商品情報を管理
- プラグイン依存(SEO、構造化データ、サイトマップ)
- サーバーサイドレンダリング
After(Astro SSG)
- MDXファイルとして商品情報を管理
- コードベースでSEO、構造化データを制御
- 静的サイト生成(ビルド時に全ページ生成)
なぜAstroを選んだか
- ビルド時に全ページが生成される: サーバー不要、ホスティングコストが最小
- MDXサポート: Markdownにコンポーネントを埋め込める
- Islands Architecture: 必要な部分だけインタラクティブにできる
CSVからMDXへの自動生成パイプライン
データ構造
商品情報をCSVで管理し、そこからMDXファイルを生成する方式にしました。
1id,name,country,roast_level,series,scene,description,price,weight2eth-yirgacheffe,エチオピア イルガチェフェ,エチオピア,浅煎り,シングルオリジン,朝のひととき,フローラルな香りと...,1200,2003col-supremo,コロンビア スプレモ,コロンビア,中煎り,シングルオリジン,リラックスタイム,ナッツのような...,1100,200生成スクリプト
CSVを読み込み、各行をMDXファイルとして出力するスクリプトをClaude Codeで作成しました。
1// generate-brand-mdx.js(簡略版)2import { parse } from 'csv-parse/sync';3import fs from 'fs';4import path from 'path';5
6const csvData = fs.readFileSync('brands.csv', 'utf-8');7const records = parse(csvData, { columns: true });8
9for (const record of records) {10 const mdx = generateMDX(record);11 const outputPath = path.join('astro/src/content/brand', `${record.id}.mdx`);12 fs.writeFileSync(outputPath, mdx);13}14
15function generateMDX(record) {13 collapsed lines
16 return `---17name: "${record.name}"18country: "${record.country}"19roastLevel: "${record.roast_level}"20series: "${record.series}"21scene: "${record.scene}"22price: ${record.price}23weight: ${record.weight}24---25
26${record.description}27`;28}MDXの格納先
生成されたMDXファイルはastro/src/content/brand/に格納されます。AstroのContent Collectionsとして扱い、型安全にデータを取得できます。
バッチ処理のセッション管理戦略
なぜバッチ処理が必要だったか
28商品を一度に処理しようとすると、Claude Codeのコンテキストウィンドウが逼迫します。特に以下の作業を1セッションで行うのは非現実的でした。
- MDXファイルの生成
- 各商品の個別カスタマイズ(説明文の微調整)
- 画像の対応付け
- ビルドエラーの修正
8-10件ずつのバッチ処理
セッションを分けて、8〜10商品ずつ作成する方針にしました。
1セッション1: 商品 1-102セッション2: 商品 11-203セッション3: 商品 21-28各セッションの冒頭で「前回のセッションで商品1-10のMDXファイルを作成済みです。今回は商品11-20を同じ形式で作成してください」と指示します。
バッチ処理で注意した点
- フォーマットの一貫性: 最初のバッチで作成したMDXファイルを「テンプレート」として次のセッションに渡す
- ファイル名の命名規則:
{国名}-{品種名}.mdxのルールを毎回伝える - ビルド確認: 各バッチ完了後に
astro buildを実行してエラーがないか確認
一覧ページの自動生成
複数の切り口での一覧
商品データを複数の軸で一覧表示するページを実装しました。
- 国別一覧: エチオピア、コロンビア、ブラジル…
- 属性別一覧(複数の分類軸で商品を整理)
- シリーズ別一覧: シングルオリジン、ブレンド
- おすすめシーン別一覧: 朝のひととき、リラックスタイム、ギフト
1---2import { getCollection } from 'astro:content';3
4export async function getStaticPaths() {5 const brands = await getCollection('brand');6 const countries = [...new Set(brands.map(b => b.data.country))];7 return countries.map(country => ({8 params: { country },9 props: { brands: brands.filter(b => b.data.country === country) }10 }));11}12
13const { brands } = Astro.props;14---AstroのContent Collectionsを使うと、このような動的ルーティングが型安全に書けます。
ページネーション
一覧ページにはAstro標準のページネーション機能を使いました。
1---2export async function getStaticPaths({ paginate }) {3 const brands = await getCollection('brand');4 return paginate(brands, { pageSize: 12 });5}6const { page } = Astro.props;7---SEO対策
JSON-LD構造化データ
5種類の構造化データを実装しました。
| スキーマ | 用途 |
|---|---|
| Product | 各商品の詳細情報 |
| Article | ニュース記事 |
| Breadcrumb | パンくずリスト |
| FAQ | よくある質問 |
| LocalBusiness | 店舗情報 |
1// 構造化データの生成例(Product)2function generateProductJsonLd(brand) {3 return {4 "@context": "https://schema.org",5 "@type": "Product",6 "name": brand.name,7 "description": brand.description,8 "image": brand.image,9 "offers": {10 "@type": "Offer",11 "price": brand.price,12 "priceCurrency": "JPY",13 "availability": "https://schema.org/InStock"14 }15 };1 collapsed line
16}サイトマップ
Astroの@astrojs/sitemapインテグレーションで自動生成しています。商品ページ、一覧ページ、ニュース記事を全て含めます。
移行スクリプト
ニュース記事の移行
WordPressのニュース記事(お知らせ、新商品情報)はnews-migration-simple.jsで移行しました。
1// news-migration-simple.js(概要)2// 1. WordPressのエクスポートXMLを読み込み3// 2. 各記事のタイトル、本文、日付、カテゴリを抽出4// 3. Astro Content CollectionsのMDXフォーマットで出力画像の移行
WordPressのメディアライブラリから画像を一括コピーするスクリプトも作成しました。ファイル名の正規化(日本語→英数字、スペース→ハイフン)も同時に行います。
PWA対応
Service WorkerとManifest
オフラインでもメニューを閲覧できるよう、PWA対応を実施しました。
manifest.json: アプリ名、アイコン、テーマカラー- Service Worker: 静的アセットのキャッシュ戦略
移行の成果
| 項目 | WordPress | Astro SSG |
|---|---|---|
| ビルド時間 | — | ※要確認 |
| ページ数 | ※要確認 | 商品28 + 一覧ページ + ニュース記事 |
| Lighthouse Performance | ※要確認 | ※要確認 |
| ホスティングコスト | ※要確認 | 静的ホスティング(低コスト) |
WordPress時代と比較して、ページの表示速度は体感で大幅に改善しました。静的サイトのため、サーバーダウンのリスクもなくなっています。
学んだこと
CSVドリブンなコンテンツ管理の有効性
商品情報をCSVで一元管理し、そこからMDXを生成する方式は、ECサイトのようなカタログ型コンテンツに適しています。新商品の追加はCSVに1行追加してスクリプトを実行するだけです。
バッチ処理のセッション管理は必須
28件程度の規模でも、1セッションで全てを処理するのは非現実的でした。AIとの作業では「1セッションのスコープを限定する」ことが品質を保つコツです。
AI移行の向き不向き
- 向いている: データ構造が明確なコンテンツの変換、テンプレートベースのページ生成、SEO構造化データの実装
- 向いていない: デザインの微調整(パターン1で述べた問題)、WordPressプラグイン固有の機能の再実装