• #Nuxt
  • #Vue
  • #移行
  • #Vuetify
  • #Pinia
  • #Cloudflare
開発eurekapuアクティブ

cockpit-nuxt-vuetify Nuxt 4 移行計画

背景

Herokuで運用中のcockpit-nuxt-vuetify(月額$7)をCloudflareに移行したいが、Nuxt 2 SSRをそのままCloudflare Pagesで運用するのは現実的でない。Nuxt 2自体のサポートは2024年6月30日に終了(公式LTS)しており、2026-02-15時点の最新安定版はNuxt 4.3.1。Nuxt 4への移行が必要。

現在のHeroku構成

Heroku ダッシュボード - warm-plains-36011

項目
アプリ名warm-plains-36011
GitHubkeikomatsu/cockpit-nuxt-vuetify
DynoBasic ($7/月)
起動コマンドnpm run start
デプロイ回数199回

なぜ Cloudflare Pages に移行するか

  1. コスト削減: Heroku Basic Dyno $7/月 → Cloudflare Pages 無料
  2. パフォーマンス: Cloudflareのグローバルエッジネットワーク
  3. 簡単なデプロイ: GitHubとの自動連携
  4. 無料SSL: 自動でHTTPS化

移行方針: 新規プロジェクト立ち上げ

既存コードを書き換えるのではなく、新規Nuxt 4プロジェクトをゼロから作成し、必要な機能だけを移植する。

この方式のメリット

  1. 799ページ全部を移行しなくて良い - 必要なものだけ選んで移植
  2. UIを刷新できる - Vuetify 3のデザインをフル活用
  3. 技術的負債を持ち込まない - リファクタリングしながら進められる
  4. 段階的に切り替え可能 - 移行完了したページから順次公開

現状のトップページ構造

トップページ(pages/index.vue)には以下のコンテンツカードがある:

外部リンク(移行が簡単)

カテゴリ内容移行難易度
Udemy動画講座8講座へのリンク簡単
Kindle本2冊へのリンク簡単

Udemy講座一覧:

  • 日商簿記3級編
  • 会計・簿記入門編
  • Excelショートカット編
  • 財務3表編
  • Excel基礎編
  • Excelで財務三表編
  • Excelでキャッシュフロー精算表
  • Excelで連結会計入門

内部コンテンツ(静的ページ)

コンテンツURL移行難易度
会計・簿記入門編/lessons/intro-to-accounting/
日商簿記3級_講義テキスト/lessons/bookkeeping/chapter*/
日商簿記3級_スライド/lessons/bookkeeping/slides/
Excelショートカット編/lessons/excel-shortcuts/
財務3表編/lessons/financial-statements/

動的コンテンツ(問題集・テスト)

コンテンツURL移行難易度
仕訳問題_分野別/sampleTest/boki3SampleTestByField
日商簿記3級問題編/workbook/boki3
帳簿問題/workbook/continuousQuestions

: Firebase認証のコードは存在するが、ルートレベルの保護がなく実質的に未使用。未認証でもページにアクセス可能(空白表示になるだけ)。移行時に認証機能を実装するかは要検討。

旧プロジェクト規模(参考)

項目数量備考
ページ数799全部は移行しない
コンポーネント数219必要なものだけ移植
Vuexストア23ファイルPiniaで再設計
Vuetifyグリッド使用9,394箇所新規で書き直し

移行戦略: 段階的リリース

Phase 1: 基盤構築 + トップページ

目的: 新Nuxt 4プロジェクトをCloudflareにデプロイ、トップページを公開

  • 新規リポジトリ作成(C:\Users\numbe\Git_repo\eurekapu-nuxt4
  • Nuxt 4プロジェクト作成(npx nuxi@latest init
  • Vuetify 3セットアップ(vuetify-nuxt-module v0.19+)
  • Cloudflare Pagesデプロイ設定
  • トップページ作成(Udemy/Kindleリンクカード)
  • 基本レイアウト・ナビゲーション

技術スタック:

Nuxt 4.x
├── Vuetify 3(vuetify-nuxt-module v0.19+)
├── Pinia(状態管理)
└── Cloudflare Pages(ホスティング)

Nuxt 4のディレクトリ構造:

Nuxt 4ではアプリケーションコードが app/ ディレクトリに格納される。

eurekapu-nuxt4/
├── app/
│   ├── assets/
│   ├── components/
│   ├── composables/
│   ├── layouts/
│   ├── middleware/
│   ├── pages/
│   ├── plugins/
│   └── utils/
├── server/
├── public/
├── nuxt.config.ts
└── package.json

nuxt.config.ts:

export default defineNuxtConfig({
  compatibilityDate: '2025-01-01',
  nitro: {
    preset: 'cloudflare_pages'
  },
  modules: [
    'vuetify-nuxt-module',
    '@pinia/nuxt'
  ],
  routeRules: {
    // 移植済みページを明示的にSSGプリレンダリング
    '/': { prerender: true },
    '/lessons/bookkeeping/**': { prerender: true },
    '/lessons/excel-shortcuts/**': { prerender: true },
    '/lessons/financial-statements/**': { prerender: true },
    '/lessons/intro-to-accounting/**': { prerender: true },
    // 問題集など動的コンテンツはCSR(サーバー不要)
    '/workbook/**': { ssr: false },
    '/sampleTest/**': { ssr: false },
  }
})

Phase 2: 静的コンテンツ移植

目的: 主要な講義テキストを移植

優先順位:

  1. /lessons/bookkeeping/ - 日商簿記3級(最もアクセスが多いはず)
  2. /lessons/excel-shortcuts/ - Excelショートカット
  3. /lessons/financial-statements/ - 財務3表
  4. /lessons/intro-to-accounting/ - 会計・簿記入門

移植方法:

  • 既存の.vueファイルからコンテンツ(データ)を抽出
  • 新しいコンポーネント構造で再実装
  • UIはVuetify 3で刷新

Phase 3: 問題集・テスト機能

目的: 復習アプリ・問題集機能を移植

  • /sampleTest/ - サンプルテスト
  • /workbook/boki3 - 仕訳問題

認証について: Firebase認証は廃止。現状のFirebase認証はルート保護すらされておらず実質未使用。新規プロジェクトには移植しない。将来的にアプリ内ユーザー認証が必要になれば別途設計する(Cloudflare Accessはサイト入口の制御であり、アプリ内認証の代替ではない点に注意)。

URL戦略

方針: 主要URLは維持、細かいのは整理

# 維持するURL
/lessons/bookkeeping/...  → そのまま
/lessons/excel-shortcuts/ → そのまま

# 整理するURL(リダイレクト設定)
/lessons/bookkeeping/chapter01/00-bspl → /boki3/1/bspl(短縮案)

SEO対応

  • 旧→新URL対応表を作成(アクセス上位ページ分)
  • public/_redirects に301リダイレクトを設定
  • 各ページに canonical タグを設定
  • 新サイトのサイトマップを生成・Search Consoleに送信

Cloudflareリダイレクト設定

public/_redirects:

# 旧URL → 新URL(URL構造を変更した場合のみ)
/old-path  /new-path  301

旧サイトからの切り替え

Step 1: 新サイトを別ドメインで公開

新: cockpit.pages.dev(Cloudflare)
旧: app.eurekapu.com(Heroku)← まだ稼働

Step 2: 動作確認

  • 移植済みページのURLスモークテスト(200応答確認)
  • 旧→新URLの301リダイレクト検証
  • Search Consoleでサイトマップ送信・インデックス状況確認

Step 3: ドメイン切り替え

新: app.eurekapu.com(Cloudflare)
旧: 停止

DNS TTL: 切り替え前にTTLを短く(300秒程度)設定し、問題発生時に即戻せるようにする。

Step 4: ロールバック条件

切り替え後に以下の状況が発生した場合、Cloudflare Pagesのロールバック機能またはDNSをHerokuに戻す:

  • 主要ページで404/500エラーが多発
  • Search Consoleでインデックス激減

Step 5: Heroku削除

切り替え後1-2週間の安定運用を確認した後、Herokuを停止。月額$7の節約完了。

費用比較

項目HerokuCloudflare Pages (Free)
月額費用$7 (Basic Dyno)$0(静的配信のみ)
帯域幅制限なし無制限
ビルド回数-500回/月
同時ビルド11

: SSG(静的生成)のみであればFunctions課金は発生しない。SSR/Functionsを使う場合はWorkers課金枠(Free: 日10万リクエスト上限)に入るため、本プロジェクトはSSG前提で$0を維持する。

トラブルシューティング

ビルドエラー: Node.js バージョン

Cloudflare Pages Build Image v3のデフォルトはNode.js 22系。再現性のため .node-version または NODE_VERSION 環境変数でバージョンを固定する:

NODE_VERSION=22

404エラー

SSGの場合、原因を以下の順で切り分ける:

  1. 静的配信: ビルド出力(.output/public/)に該当HTMLが生成されているか確認
  2. routeRules: nuxt.config.tsrouteRules でプリレンダリング対象に含まれているか確認
  3. リダイレクト: public/_redirects のルールが意図通りか確認

_routes.json はPages Functions(SSR)の呼び出し制御用。SSGのみの場合は関係しない。

API呼び出しのCORSエラー

Cloudflareのドメインからのリクエストを許可するよう、APIサーバー側のCORS設定を更新。

工数見積もり(Claude Code実装前提)

Claude Codeが旧プロジェクトの.vueファイルを読み取り、Nuxt 4 + Vuetify 3形式に変換する。アクセス解析で確認済みの高トラフィックページのみを対象とする。

フェーズ期間備考
Phase 1: 基盤 + トップページ1日nuxi init + Vuetify設定 + Cloudflareデプロイ
Phase 2: コンテンツ移植1-2日/セクション旧.vueから自動変換、アクセス上位のみ
Phase 3: 問題集・テスト1-2日認証なし、CSRで実装

※ Firebase認証は廃止。移行対象外。

移植しないもの(廃止候補)

調査で見つかった、おそらく不要なコンテンツ:

  • pages/testPage/ - テスト用
  • components/test/ - テスト用コンポーネント
  • store/testtest.js, store/hoge-module.js - 未使用ストア
  • pages/tbd/, pages/tbd02/ - 未完成コンテンツ

リポジトリ構成

C:\Users\numbe\Git_repo\
├── cockpit-nuxt-vuetify/   ← 旧プロジェクト(Nuxt 2、Heroku)※移行完了後に廃止
├── mdx-playground/          ← ブログ・コンテンツ管理(現プロジェクト)
└── eurekapu-nuxt4/          ← 新規作成(独立リポジトリ)
  • 新規の独立Gitリポジトリとして eurekapu-nuxt4 を作成
  • mdx-playgroundとは別管理。デプロイ・CI/CDも独立
  • GitHub: 新規リポジトリを作成し、Cloudflare Pagesと連携

次のアクション

  1. C:\Users\numbe\Git_repo\eurekapu-nuxt4 に新規リポジトリ作成
  2. npx nuxi@latest init でNuxt 4プロジェクト初期化
  3. Vuetify 3 + Pinia セットアップ
  4. Cloudflare Pagesデプロイ確認
  5. トップページ(Udemy/Kindleリンクカード)実装
  6. アクセス上位の講義ページから移植開始

CSSフレームワークの検討: Vuetify vs Tailwind

結論: Vuetify 3 を採用

Tailwind CSS への移行も検討したが、Vuetify 3 を採用することに決定。

比較検討

項目Vuetify 3Tailwind CSS
性質コンポーネントライブラリCSSユーティリティ
フォーム<v-text-field> で完結自作 or ライブラリ追加
ダイアログ<v-dialog>Headless UI等が必要
テーブル<v-data-table>自作
カード<v-card>div + Tailwindクラス

Vuetify 3 を選んだ理由

  1. 問題集・テスト機能との相性
    • フォーム入力、バリデーション、正誤判定のUIが必要
    • Vuetifyならコンポーネントが揃っている
  2. 新規プロジェクト方式のメリット
    • Vuetify 2→3 の互換性問題は既存コードを引きずらないので軽微
    • 旧プロジェクトの構造を参考にしつつ、クリーンに実装可能
  3. 開発効率
    • UIコンポーネントを自作する必要がない
    • 定型的なコードで速く書ける

Tailwind が向いているケース(参考)

  • マーケティングサイト、LP(見た目重視、機能少なめ)
  • デザイナーがいて独自デザインを追求したい
  • 軽量さが最優先

このプロジェクトは「学習コンテンツ + 問題集」という機能系UIが多いため、Vuetifyの方が適している。

レビュー・意思決定ログ(2026-02-15)

確定事項

項目決定理由
レンダリングSSG前提(ハイブリッド)教育コンテンツは更新頻度低。問題集のみCSR
Firebase認証廃止ルート保護なし、実質未使用。移植しない
コンテンツ形式.vueファイル維持インタラクティブな要素が多く、Markdown化は困難
移行スコープアクセス上位ページのみGA/Search Console確認済み。限定的に移行
実装主体Claude Code旧.vueファイルの自動変換で高速に移植

参考リンク