Vercel v0で生成したコンポーネントを実際に動かすための開発環境づくり

# 概要

Vercel v0はReactベースで生成AIを活用してUIコンポーネントを生成できます。この記事では、Vite、Remix、Tailwindを使って、Vercel v0で生成されたコンポーネントを動かすための開発環境を構築していきます。
Shadcnは、必要なUIコンポーネントのみをCLIなどでプロジェクトへコピーすることで、不要なコードを排除し、パフォーマンスを最大化するというアプローチを採用しています。
React,shadcn,tailwindを選ぶときに、生成AI(v0)を活用しやすいということも、一つの選定理由となるかと思います。

# ViteとRemixのセットアップ

まず、ViteとRemixを使って開発環境をセットアップします。以下の手順でプロジェクトを作成します。

```bash
bun create vite my-v0-app
✔ Select a framework: › React
✔ Select a variant: › Remix ↗

 remix   v2.12.1 💿 Let's build a better website...
      ◼  Directory: Using my-v0-app as project directory

      ◼  Using basic template See https://remix.run/guides/templates for more
      ✔  Template copied

   git   Initialize a new git repository?
         Yes

  deps   Install dependencies with bun?
         Yes

      ✔  Dependencies installed

      ✔  Git initialized

  done   That's it!

         Enter your project directory using cd ./my-v0-app
         Check out README.md for development and deploy instructions.
```

https://ui.shadcn.com/docs/installation/remix

# Shadcnのセットアップ

次に、UIコンポーネントライブラリであるShadcnをプロジェクトに追加します。ShadcnはTailwind CSSをベースにしたコンポーネントライブラリで、Vercel v0で生成されたコンポーネントをカスタマイズしたり、新しいUI要素を素早く作成したりするのに非常に適しています。

1. **Shadcnの初期化**: 以下のコマンドでShadcnを初期化します。
    ```bash
    bunx shadcn@latest init
    ```
    
    初期化プロセス中に、テーマの選択やCSS変数の使用についての質問に答えると、プロジェクトに必要なファイルが自動で生成されます。
    
    ```bash
    ✔ Preflight checks.
    ✔ Verifying framework. Found Remix.
    ✔ Validating Tailwind CSS.
    ✔ Validating import alias.
    ✔ Which style would you like to use? › New York
    ✔ Which color would you like to use as the base color? › Zinc
    ✔ Would you like to use CSS variables for theming? … no / yes
    ✔ Writing components.json.
    ✔ Checking registry.
    ✔ Updating tailwind.config.ts
    ✔ Updating app/tailwind.css
    ✔ Installing dependencies.
    ✔ Created 1 file:
      - app/lib/utils.ts
    ```

2. **Tailwind CSSの設定**: Tailwind CSSとAutoprefixerをプロジェクトに追加します。
    
    ```bash
    bun add -D tailwindcss@latest autoprefixer@latest
    ```
    
3. **`tsconfig.json`の設定**:
    `tsconfig.json`の`compilerOptions.paths`に必要な設定を追加します。
    ```bash
    "compilerOptions": {
      "baseUrl": ".",
      "paths": {
        "@/*": ["./app/*"]
      }
    }
    ```

# Vercel v0でコンポーネントを生成

[Vercel v0](https://v0.dev/chat)を使ってUIパーツを生成します。たとえば、以下のプロンプトでBMI計算機を作成できます。

https://v0.dev/chat/wwdfQTflDma?b=b_izx5m3k5ao3

## プロンプトの例

```bash
BMIを算出するサイト 身長と体重を入力する BMI=体重(kg)/(身長(m)^2) BMIを表示して、18.5~25未満であれば適正とする
```

## 生成されたコンポーネントの画像
![Screenshot 2024-09-26 161600.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149838/2c7ac254-8c90-19a8-c13c-46d3cf8f76b7.png)

## 生成されたコード

```bash
import { useState } from 'react'
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"

export default function BMICalculator() {
  const [height, setHeight] = useState('')
  const [weight, setWeight] = useState('')
  const [bmi, setBMI] = useState<number | null>(null)

  const calculateBMI = () => {
    const heightInMeters = Number(height) / 100
    const weightInKg = Number(weight)
    
    if (heightInMeters > 0 && weightInKg > 0) {
      const calculatedBMI = weightInKg / (heightInMeters * heightInMeters)
      setBMI(Number(calculatedBMI.toFixed(2)))
    } else {
      setBMI(null)
    }
  }

  const getBMICategory = (bmi: number) => {
    if (bmi < 18.5) return '低体重'
    if (bmi >= 18.5 && bmi < 25) return '適正'
    if (bmi >= 25 && bmi < 30) return '過体重'
    return '肥満'
  }

  return (
    <div className="max-w-md mx-auto mt-10 p-6 bg-white rounded-lg shadow-xl">
      <h1 className="text-2xl font-bold mb-6 text-center">BMI計算機</h1>
      <div className="space-y-4">
        <div>
          <Label htmlFor="height">身長 (cm)</Label>
          <Input
            id="height"
            type="number"
            value={height}
            onChange={(e) => setHeight(e.target.value)}
            placeholder="身長を入力してください"
          />
        </div>
        <div>
          <Label htmlFor="weight">体重 (kg)</Label>
          <Input
            id="weight"
            type="number"
            value={weight}
            onChange={(e) => setWeight(e.target.value)}
            placeholder="体重を入力してください"
          />
        </div>
        <Button onClick={calculateBMI} className="w-full">BMIを計算</Button>
      </div>
      {bmi !== null && (
        <div className="mt-6 p-4 bg-gray-100 rounded-md">
          <p className="text-lg font-semibold">あなたのBMI: {bmi}</p>
          <p className="mt-2">
            判定: <span className={`font-bold ${getBMICategory(bmi) === '適正' ? 'text-green-600' : 'text-red-600'}`}>
              {getBMICategory(bmi)}
            </span>
          </p>
        </div>
      )}
    </div>
  )
}
```

# Shadcnコンポーネントの追加

生成したコンポーネントを `app/components` へ配置します。
右上のAdd to Codebaseから作成されたコマンドを使えば簡単にリポジトリへ生成されたコンポーネントと必要なShadcnのUIコンポーネントを追加できます。

![Screenshot 2024-09-27 095609.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149838/55ee4107-a3cc-e8f0-4a0a-1e56c1ba702e.png)

```bash
npx shadcn@latest add "https://v0.dev/chat/b/b_izx5m3k5ao3?token=xxx"
✔ Checking registry.
✔ Installing dependencies.
✔ Created 4 files:
  - app/components/bmi-calculator.tsx
  - app/components/ui/button.tsx
  - app/components/ui/input.tsx
  - app/components/ui/label.tsx
```

通常のshadcn addを使ってUIコンポーネントを追加場合は以下のようにコンポーネント名を指定します。

```bash
bunx shadcn add button
```

https://ui.shadcn.com/docs/cli

あとは利用したい箇所でコンポーネントをインポートして、 `bun run dev` で動作を確認できます。


# ディレクトリ構成

最終的なディレクトリ構成は以下のようになります。Shadcnで追加したパーツは`components/ui`配下に追加されます。

```bash
├── README.md
├── app
│   ├── components
│   │   ├── bmi-calculator.tsx
│   │   └── ui
│   │       ├── button.tsx
│   │       ├── input.tsx
│   │       └── label.tsx
│   ├── entry.client.tsx
│   ├── entry.server.tsx
│   ├── lib
│   ├── root.tsx
│   ├── routes
│   └── tailwind.css
├── build
│   ├── client
│   └── server
├── bun.lockb
├── components.json
├── node_modules
├── package.json
├── postcss.config.js
├── public
│   ├── favicon.ico
│   └── logo-light.png
├── tailwind.config.ts
├── tsconfig.json
└── vite.config.ts
```

# まとめ

これで、Vercel v0で生成されたコンポーネントを動作させるための開発環境が整いました。
shadcn CLIを使うことで、Vercel v0のコンポーネントを簡単にインポートできるようになっており、なかなか面白いUXかと思います。

詳細な手順や設定方法については、以下のリンクを参照してください
- https://ui.shadcn.com/docs/installation