Claude 3.5 Sonnet Artifactsで爆速アプリ開発してみた

# 概要
2024年6月21日、Anthoropic社から「Claude 3.5 Sonnet」がリリースされました。
その際に、「Artifacts」という機能が登場し、生成されたコードや図を専用のウィンドウに表示することが可能になりました。
[Introducing Claude 3.5 Sonnet \ Anthropic](https://www.anthropic.com/news/claude-3-5-sonnet)

本記事は、Claude 3.5 Sonnet Artifactsを利用した単語帳アプリ作成の記録です。

# 環境
- マシン：Mac mini (チップ：Apple M2 Pro)
- エディタ：Cursor (バージョン：0.34.4)

## 言語・パッケージ等
- Node.js: 22.2.0
- React: 18.3.1
- Typescript: 5.5.2
- Vite: 5.3.2
- json-server: 1.0.0-beta.1
- Tailwind CSS: 3.4.4

# アプリの構成
- バックエンド：json-server
- フロントエンド：React + TypeScript + Vite + shadcn/ui

# アプリ作成手順
## Claude 3.5 Sonnet ArtifactsにReactコードを生成させる
まずはClaudeにログインし、Artifactsモードをオンにします。

:::note info
2025/1/23 ClaudeのUI変更を反映
:::

画面左下、自分自身のアカウント名の右にある「▽」 を押下し、「Settings」を選択します。
![Claude_setting.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/f7308fa0-73f5-91c5-9f8e-31ab946a7217.png)

遷移した画面のサードバーで「プロファイル」を選択し、画面下方の「Enable artifacts」のトグルボタンをオンにすると、Artifactsモードを利用できるようになります。
![Claude_Settings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/fa797a41-70e4-b5f2-ddfd-a7bf19611841.png)


さて、適当にプロンプトを入力すると、画面右半分のウィンドウにコードを出力していきます。
![Claude_Code.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/c681ec74-d226-50db-40ba-9f1ae2dfca2c.png)

コードの生成が終了すると、画面イメージを表示してくれます。
![Claude_screen_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/9f9ae416-2653-0a0c-7137-5235a77f1d51.png)

この画面イメージは操作可能で、例えばテキストエリアに文字を入力して「追加」ボタンを押下すると...
![Claude_input.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/5cecff4f-919f-2510-7dda-4399b39f3bd1.png)

単語が追加されました。
![Claude_input_result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/e09891d8-4862-4ebd-a408-533bb35d8715.png)


このように、生成された画面イメージを操作しながら確認し、適宜追加で指示をしていきます。

:::note warn
注意点
Claudeの実行環境にインストールされていないパッケージを使用しようとすると、画面イメージが表示されません。
![Claud_error.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/db0b38bb-e96d-c9cb-e85d-7ca2398b4bd3.png)

:::

そのため、今回は以下の方針でコードを生成させました。
- Claudeにはアプリの画面を1枚ずつ生成させ、ルーティングは記述させないようにする
- ルーティングはreact-router-domを用いて、Claudeが生成したコードに対し、手作業でコードを追記する

## Viteを用いてアプリを構築する
### Viteを使用する理由
以前、Claude 3 Opusを利用してアプリ作成をした際にNext.jsを用いたところ、Server-side Rendering/Client-side Renderingを考慮しないコードが量産されて苦労しました。
その際にClaudeは比較的新しいフレームワークのコード生成が苦手そうに感じたので、今回はオーソドックスなReactコードを生成させることにしました。

そこで、Claude 3.5 Sonnetが出力したコードに柔軟に対応できるフレームワークとしてViteを採用しました。

### shadcn/uiの導入
ClaudeはUIコンポーネントにshadcn/uiを用いてきたので、公式サイトを参考に、Viteにshadcn/uiを追加します。
[Vite - shadcn/ui](https://ui.shadcn.com/docs/installation/vite)

ただし、公式サイトに書かれていることをそのまま実行すると、以下のようなディレクトリ構造になったので、
```
.
├── @
│   ├── components
│   │   └── ui
│   └── lib
│       └── utils.ts
(以下省略)
```
componentsディレクトリとlibディレクトリは手作業でsrcディレクトリ以下に移動しました。
```
.
├── src
│   ├── components
│   │   └── ui
│   │       ├── alert-dialog.tsx
│   │       ├── alert.tsx
│   │       ├── badge.tsx
│   │       ├── button.tsx
│   │       ├── card.tsx
│   │       ├── input.tsx
│   │       └── textarea.tsx
│   ├── lib
│   │   └── utils.ts
(以下省略)
```
`npx shadcn-ui@latest add`コマンドでコンポーネントを追加すると、@ディレクトリ以下のcomponents/uiディレクトリ以下にtsxファイルが追加されますが、都度src配下のcomponents/uiディレクトリに移動しました。

### ページ作成およびルーティング設定
 srcディレクトリ配下にpagesフォルダを作成し、Claudeに生成させたコードを1枚ずつ格納します。
 ```
.
├── src
│   ├── components
│   ├── lib
│   ├── assets
│   ├── pages
│   │   ├── FlashcardPage.tsx
│   │   ├── SubjectListPage.tsx
│   │   ├── TagListPage.tsx
│   │   └── TestPage.tsx
│   ├── App.css
│   ├── App.tsx
│   ├── index.css
│   ├── main.tsx
│   ├── types.ts
│   └── vite-env.d.ts
(以下省略)
 ```
次に、コンポーネント同士を連携させ、ルーティングを設定していきます。
```react:main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './index.css'
import { BrowserRouter } from "react-router-dom";


ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>,
)

```
```react:App.tsx
import SubjectListPage from './pages/SubjectListPage'
import FlashcardPage from './pages/FlashcardPage';
import TestPage from './pages/TestPage';
import TagListPage from './pages/TagListPage';
import './App.css'
import { Routes, Route } from "react-router-dom";

function App() {

  return (
    <div>
      <Routes>
        <Route path="/" element={<SubjectListPage/>}/>
        <Route path="/flashcard">
          <Route path=":subjectId" element={<FlashcardPage/>}/>
        </Route>
        <Route path="/test">
          <Route path=":subjectId" element={<TestPage/>}/>
        </Route>
        <Route path="/tag" element={<TagListPage/>}/>
      </Routes>
    </div>
  )
}

export default App
```
Claudeの生成したコードはボタンの押下で画面遷移をするようになっていたので、react-router-domのuseNavigateを利用します。
```react:SubjectListPage.tsx
import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import axios from "axios";

// 省略

const SubjectListPage = () => {
  const navigate = useNavigate();

  // 省略
  
  const goToTagList = () => {
    navigate('/tag');
  };
  
  return (
    <div className="container mx-auto p-4">
        <div className="flex justify-between items-center mb-4">
        <h1 className="text-2xl font-bold mb-4">単語帳アプリ</h1>
            <Button onClick={goToTagList} variant="outline">
                <Tag className="mr-2 h-4 w-4" />
                タグ一覧
            </Button>
        </div>

        {/* 省略 */}
      
    </div>
  );
};

export default SubjectListPage;
```
### json-server設定
Claudeが最初に生成したコードはテストデータがハードコーディングされていたので、以下の記事を参考にjson-serverを構築します。
[json-serverの使い方まとめ【解説】](https://qiita.com/ryome/items/36da51f0f5973eab8720)

Claudeにお願いすると、json-server用のJSONファイルを書いてくれるので、そのままdb.jsonにコピペします。
![Claude_json_server.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/c5bd656d-9891-c75e-abd5-d59bcf031541.png)


更に、Claudeにお願いすると、すでに生成してくれたコードを修正して、json-serverとの繋ぎ込みを記述してくれます。
![Claude_code_update.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/ac5ab93e-2d26-7932-65ba-d61810fcc172.png)
コードをコピペして、ルーティング設定を書き加えました。

# 参考：アプリケーション画面
トップページ
![Flashcard_app_top.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/eee4f397-fa14-cd0b-ce8b-031b574163d9.png)

単語帳ページ
![Flashcard_app_flashcards.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/cb8488b9-e05a-7f60-199d-4c59f33eb5c5.png)

テストページ
![Flashcard_app_test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/92bc63d0-8875-f336-bee3-1d4b684ff77b.png)

タグ一覧ページ
![Flashcard_app_tags.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/e9cc744d-683a-2301-5ad6-07116af1a7fb.png)

# 感想
体感2、3時間程度でアプリを作成できました。
画面デザインのクオリティも満足しています。
作成の過程でエラーに悩まされるイライラが激減し、アプリ作成の楽しい部分だけを煮詰めたような製作になりました。
今後のアプリの個人製作はClaude 3.5 Sonnet Artifactsが必須になりそうです。