Cursorで『レガシーコード』を解体・再構築する:jQuery/レガシーJSからReact/TypeScriptへの超高速マイグレーション支援AI活用術
開発プロジェクトを率いるテックリードの皆さん、あるいは現場で技術的負債と日々格闘しているシニアエンジニアの皆さん、お疲れ様です。
システムが長年生き続け、事業に貢献してきた証とも言える「レガシーコード」。しかし、手作業でのマイグレーション(例:jQueryや生DOM操作が入り組んだ古いJavaScriptから、React + TypeScriptへの移行)は、果てしないテスト、複雑な暗黙的依存関係の紐解き、そしてタイピングの単純作業に追われ、開発チームの生産性とモチベーションを著しく低下させます。
単なるコード補完エディタの枠を超えたAIネイティブIDE「Cursor」は、このマイグレーションの景色を完全に変えました。
本記事では、単なる「AIにコードを書かせる」レベルを超え、レガシーシステムの設計思想を分析・保持しながら、安全かつ爆速で現代的なアーキテクチャ(React / TS)へ安全に移行するための、アーキテクト目線の実践的ワークフローを徹底解説します。
—
1. なぜマイグレーションにCursorが圧倒的な威力を発揮するのか?
単一ファイルのコードを別言語に書き換えるだけであれば、従来型のLLMチャットでも可能です。しかし、実務のマイグレーションで事故が起きる原因は、「ファイル外に隠された暗黙の依存関係」と「プロジェクト固有の設計規約の欠落」にあります。
【従来の移行アプローチ】
古いJSコードを読む ➔ 依存関係を脳内デバッグ ➔ 型を推測 ➔ 手動でReact化 ➔ 破壊的変更が発生 ➔ バグ対応
【Cursorを活用したアーキテクチャ移行】
@Codebaseによる全体静的解析 ➔ .cursorrulesによる型/設計規約の自動適用 ➔ Composerによるコンポーネント/Hookの分離出力 ➔ コンパイラ/テスト駆動の自動修復ループ
Cursorはプロジェクト全体のコードベースをベクターインデックス化(`@Codebase`)し、ローカルのコンテキストを正確にプロンプトへ注入できます。これにより、「他のファイルで定義されているグローバル変数やCSSクラス、APIレスポンスの暗黙の構造」まで考慮した上で、TypeScriptの厳格な型定義とReactの宣言的UIへ再構築することが可能になります。
—
2. チームの規約をAIの脳内に直接叩き込む:`.cursorrules` の極意
マイグレーションを開始する前に絶対に行うべきなのが、リポジトリ直下への `.cursorrules`(または `.cursor/rules`)の設置です。これにより、AIが「書き換える際のアウトプットの品質・設計標準」を固定化します。
以下は、jQuery/レガシーJSを React + TypeScript + Tailwind CSS へ移行するプロジェクト専用に調整した `.cursorrules` のベストプラクティス設定です。
`.cursorrules` (プロジェクトルートに配置)
Migration Architecture Rules: Legacy JS to React + TypeScript
1. Role and Core Vision
あなたは当プロジェクトの「プリンシパル・フロントエンド・アーキテクト」です。
既存のレガシーコード(jQuery, Vanilla JS, Direct DOM Manipulation)を解析し、
ビジネスロジックと意図を100%保持したまま、厳格な TypeScript + React (Functional Component) へリファクタリングしてください。
2. Refactoring & Code Generation Standards
TypeScript & Types
- `any` 型の使用は厳禁とする。不明な型は `unknown` とし、Type Guard関数を同時に作成すること。
- JSDocコメント、または実行時オブジェクトの構造から、インターフェース (`interface`) を明確に抽出・定義すること。
- イベントハンドラには正確な `React.SyntheticEvent` の型を付与すること。
Component Architecture
- 1ファイル 1コンポーネントの原則を守る。
- ロジックとUIの分離: DOM操作やデータ取得、ステート変更ロジックは必ず Custom Hook (`useXxx`) に切り出すこと。
- レガシーコードに存在する「グローバル変数」「直接のDOM操作 (`$(‘#id’)`, `document.querySelector`)」は完全に排除し、Reactの `useState`, `useRef`, `useContext` に置き換えること。
Migration Code Structure Pattern
変換時は必ず以下の構造に分割して出力すること:
1. Types (`types.ts`): レガシーコードから抽出した型定義
2. Custom Hook (`useXxx.ts`): ビジネスロジックと状態管理
3. Component (`Xxx.tsx`): プレゼンテーション層(Tailwind CSSを使用)
3. Safety Guardrails
- 元のコードに存在する非同期処理 (Ajax/XHR) は、Fetch API または `TanStack Query (React Query)` パターンを適用可能なコード構造に変換すること。
- 暗黙の副作用(グローバルイベントの発火等)を発見した場合は、コード生成前に警告として明記すること。
—
3. 実践:jQueryコードを「Custom Hook + React Component」へ再構築する
具体的なレガシーコードを例に、Cursorを使った変換プロセスを実演します。
【変換対象】レガシーなjQueryコード (`legacy-user-panel.js`)
// レガシーなユーザーパネル制御 (暗黙的な状態と直接的なDOM操作のカオス)
$(document).ready(function() {
var currentUser = null;
$(‘#fetch-user-btn’).on(‘click’, function() {
var userId = $(‘#user-id-input’).val();
if (!userId) {
alert(‘User IDを入力してください’);
return;
}
$(‘#loading-spinner’).show();
$.ajax({
url: ‘/api/v1/users/’ + userId,
method: ‘GET’,
success: function(data) {
currentUser = data;
$(‘#user-name’).text(data.firstName + ‘ ‘ + data.lastName);
$(‘#user-email’).text(data.email);
$(‘#status-badge’).removeClass(‘active inactive’).addClass(data.isActive ? ‘active’ : ‘inactive’);
$(‘#loading-spinner’).hide();
},
error: function(err) {
alert(‘ユーザー情報の取得に失敗しました’);
$(‘#loading-spinner’).hide();
}
});
});
});
Prompt Engineering: Cursor Composer (`Cmd + I` / `Ctrl + I`) での指示
Cursorの Composer機能 (`Cmd + I`) を起動し、マルチファイル書き換えモードで以下のプロンプトを実行します。
@legacy-user-panel.js
上記レガシーコードを解析し、.cursorrules の規約に従って React + TypeScript コードへ変換してください。
【実行条件】
1. ビジネスロジックと状態を分離した `useUserPanel.ts` (Custom Hook) を作成する。
2. プレゼンテーション層として `UserPanel.tsx` を作成する。
3. `User` 型インターフェースを `types.ts` に切り出す。
4. UIスタイルは Tailwind CSS を使用して現代的に整えること。
Cursorが自動生成するモダンコード
① `types.ts` (型定義の抽出)
/
- レガシーAPIレスポンスから抽出したユーザーモデルの型定義
/
export interface User {
id: string;
firstName: string;
lastName: string;
email: string;
isActive: boolean;
}
export interface UseUserPanelReturn {
userId: string;
setUserId: (id: string) => void;
user: User | null;
isLoading: boolean;
error: string | null;
fetchUser: () => Promise
}
② `useUserPanel.ts` (ロジックの抽出と安全な非同期処理)
import { useState, useCallback } from ‘react’;
import { User, UseUserPanelReturn } from ‘./types’;
/
- ユーザー情報の取得と状態管理を行うカスタムフック
- (旧 $.ajax 処理および状態保持の置き換え)
/
export const useUserPanel = (): UseUserPanelReturn => {
const [userId, setUserId] = useState
const [user, setUser] = useState
const [isLoading, setIsLoading] = useState
const [error, setError] = useState
const fetchUser = useCallback(async () => {
if (!userId.trim()) {
setError(‘User IDを入力してください’);
return;
}
setIsLoading(true);
setError(null);
try {
const response = await fetch(`/api/v1/users/${encodeURIComponent(userId)}`, {
method: ‘GET’,
headers: {
‘Content-Type’: ‘application/json’,
},
});
if (!response.ok) {
throw new Error(‘ユーザー情報の取得に失敗しました’);
}
const data: User = await response.json();
setUser(data);
} catch (err) {
const message = err instanceof Error ? err.message : ‘予期せぬエラーが発生しました’;
setError(message);
} finally {
setIsLoading(false);
}
}, [userId]);
return {
userId,
setUserId,
user,
isLoading,
error,
fetchUser,
};
};
③ `UserPanel.tsx` (宣言的UIへの昇華)
import React from ‘react’;
import { useUserPanel } from ‘./useUserPanel’;
/
- ユーザーパネル・プレゼンテーションコンポーネント
/
export const UserPanel: React.FC = () => {
const { userId, setUserId, user, isLoading, error, fetchUser } = useUserPanel();
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
fetchUser();
};
return (
{error && (
)}
{user && (
{user.firstName} {user.lastName}
{user.isActive ? ‘Active’ : ‘Inactive’}
{user.email}
)}
);
};
—
4. バグ発生率をゼロに近づける「二重検証(Double Validation)プロセス」
AIが書き換えたコードをそのままブラウザで動かして手動テストするのは、プロのエンジニアのやり方ではありません。「TypeScript型チェック」と「AI自動ターミナルフィードバック」をループさせる仕組みを作ります。
[コード修正 (Composer)] ➔ [Terminal: tsc & vitest 実行] ➔ [エラー出力をCursorがパース] ➔ [自動修正プロンプト]
ターミナルログからの自動修正ワークフロー
1. Cursor内の統合ターミナル (`Ctrl + ~`) で型チェックまたはテストを実行します。
型チェックとテストの連続実行ログ
$ pnpm tsc –noEmit && pnpm test
src/components/UserPanel.tsx:18:23 – error TS2339: Property ‘fullName’ does not exist on type ‘User’.
18 text={user.fullName}
~~~~~~~~
FAIL src/components/useUserPanel.test.ts
✕ should handle fetch error correctly (45ms)
2. ターミナル上でエラーテキストをドラッグ選択し、`Shift + Cmd + i` (またはターミナルの「Add to Chat / Composer」) を押下。
3. Cursor Chatにエラーログと関連ファイルが自動アタッチされるため、以下のプロンプtを入力するだけで一括修正されます。
ターミナルに出力された型エラーおよびVitestの失敗ログを解析してください。
型定義とテストコードの齟齬を解消し、修正コードを適用してください。
この「静的解析ツール(tsc/eslint) ➔ AIへのフィードバック ➔ 修正」の高速ループを回すことで、ハルシネーション(幻覚)による潜在的バグをほぼ100%排除できます。
—
5. 爆速化を実現する必修キーボードショートカット & 神プラグイン
マイグレーション作業中、マウス操作はタイムロスの最大要因です。Cursorのポテンシャルを極限まで引き出すショートカットとプラグインを厳選しました。
開発効率を爆上げするキーボードショートカット
| ショートカット (Mac) | ショートカット (Win/Linux) | 機能・用途 | 実務での活用シーン |
| :— | :— | :— | :— |
| `Cmd + K` | `Ctrl + K` | In-line Edit | 選択したレガシーコードブロックをその場で瞬時にリファクタリング |
| `Cmd + I` | `Ctrl + I` | Composer (Multi-file) | 新しいコンポーネント、Hook、型定義ファイルの一元生成・一括変更 |
| `Cmd + L` | `Ctrl + L` | Cursor Chat | `@Codebase` を使った全体設計の相談や、複雑な暗黙ロジックの解読 |
| `Cmd + Shift + J`| `Ctrl + Shift + J`| Custom Symbol/Context | `@Files`, `@Git`, `@Docs` などの文脈アタッチメニューを爆速展開 |
| `Cmd + Opt + B` | `Ctrl + Alt + B` | Build & Fix Loop | ターミナルのエラー結果をコンテキストに読み込ませて一括修復 |
マイグレーション時に絶対入れるべき VS Code / Cursor 厳選プラグイン
1. Error Lens (`usernamehw.error-lens`)
- 役割: コンパイルエラーや型エラーをエディタの行内に直接デカデカと表示。
- AI連携効果: エラー箇所で即座に `Cmd + K` を押し、「This errorを修正して」と打つだけで修復完了。
2. GitLens (`eamodio.gitlens`)
- 役割: レガシーコードの「最終更新日」と「コミット理由」をコード行ごとに表示。
- AI連携効果: 「なぜこの不自然な処理(if文)が存在するのか」の背景をコミットメッセージから読み取り、仕様を壊さずに移行。
3. Coverage Gutters (`ryanluker.vscode-coverage-gutters`)
- 役割: テストカバー率をコードの横に色(緑/赤)で視覚化。
- AI連携効果: テストが通っていない赤色のレガシー処理を特定し、`Cmd + L` で「この分岐のUnit Testを書いて」と命じる。
—
6. チーム開発で役立つ設定共有化ルール & `.vscode/settings.json`
個人プレイで終わらせず、チーム全員が同じ精度でマイグレーションを実行できるように、リポジトリ共有用の設定ファイルを整備します。
`settings.json` のベストプラクティス構成例 (`.vscode/settings.json`)
{
// — TypeScript & 言語サーバー最適化 —
“typescript.tsdk”: “node_modules/typescript/lib”,
“typescript.enablePromptUseWorkspaceTsdk”: true,
“editor.codeActionsOnSave”: {
“source.organizeImports”: “explicit”,
“source.fixAll.eslint”: “explicit”
},
// — Cursor AI 機能のチーム標準化 —
// AIモデルのインデックス作成対象から除外する大型バイナリ・ビルド生成物
“cursor.general.indexingIgnore”: [
“/node_modules/“,
“/dist/“,
“/build/“,
“/.next/“,
“/coverage/“,
“/.min.js”
],
// AIによる自動提案の精度をあげるためのフォーマッタ強制
“editor.defaultFormatter”: “esbenp.prettier-vscode”,
“editor.formatOnSave”: true,
// — エラー視認性の向上 —
“workbench.colorCustomizations”: {
// 移行作業中の型エラーを目立たせてAI修復を促す
“editorError.foreground”: “#ff4242”
}
}
—
7. おわりに:テックリードが導く「AI時代のレガシーマイグレーション」
レガシーコードの刷新は、単に「古い構文を新しくする」作業ではありません。複雑に絡み合ったドメイン知識を再発見し、型という契約を結び直し、テスト可能な美しい設計へ着地させる高度なエンジニアリングです。
Cursorという強力な武器を得た今、私たちの役割は「コードを手で打ち出す作業者」から「AIへ明確な文脈と制約を与え、生成されたコードの妥当性を審査するアーキテクト」へとシフトしました。
1. `.cursorrules` で設計思想のガイドラインを敷く
2. `Composer` と `@Codebase` で文脈を保ったままロジックとUIを分解生成する
3. `tsc` や テストランナーとの高速フィードバックループで型安全性を完全担保する
この戦略をチームに導入し、数ヶ月・数年かかると諦めていた負債返済のロードマップを、数週間で完遂させる圧倒的な爆速開発体験をぜひ味わってください。