見出し画像

Turborepo と shadcn を使った React + Vite プロジェクトの構築ガイド

React アプリケーションに shadcn を統合し、さらに Turborepo のセットアップで実現したい状況に直面されたのですね。あるいは、将来的に使用することを計画して情報を得たいのかもしれません。いずれにせよ、適切な場所にたどり着きました。この記事では、そのようなセットアップに最適な構造と、実装時によくある落とし穴について説明します。

コードを直接確認したい場合は、こちらです。役立つと感じた場合は、ぜひスター🌟をつけてください。

それでは、詳細な手順をみていきましょう。

新しい Turborepo のセットアップ

pnpm dlx create-turbo@latest

注意🗒️: お察しの通り、ここではパッケージマネージャーとして pnpm を選択しています。人気のあるパッケージマネージャーであれば何を使用しても構いません。詳細については Turborepo のドキュメントを参照してください。

私の Turborepo の名前とパッケージマネージャーの選択は、それぞれ vite-shadcn-turborepo と pnpm workspaces でした。他のオプションを選択しても、問題なく以下の手順に従うことができるはずです。

デフォルトでは、Turborepo は apps ディレクトリに 2 つの Nextjs アプリケーションを提供し、packages 内に ui パッケージも含まれています。ここでは、apps 内に独自の React+Vite アプリケーションをセットアップし、ui パッケージ内に shadcn/ui を設定します。そのために、既存のボイラープレートコードを削除してクリーンアップしましょう。

Vite を使用した React アプリのセットアップ

apps ディレクトリ内の apps/docs と apps/web フォルダを削除した後、新しい Vite+React アプリを以下のコマンドで作成します:

cd apps
pnpm create vite

コマンド実行後の私の選択肢は以下の通りでした:

✔ プロジェクト名: … vite-project
✔ フレームワークの選択: › React
✔ バリアントの選択: › TypeScript + SWC
すべてが予想通りに進んだ場合、以下のコマンドを実行できるはずです:

pnpm install
pnpm run dev

これで、アプリケーションが http://localhost:5173/ で実行されているはずです。
🎉 おめでとうございます。Turborepo セットアップで Vite+React アプリを正常に実行できました。

shadcn/ui の統合

次に、shadcn/ui の部分に移ります。ここまでのように単純ではないかもしれません。shadcn を ui パッケージに配置するように Turborepo を設定します。
まず、ui パッケージに tailwindcss を追加し、次のコマンドを使用して ui パッケージ内で shadcn/ui を初期化します。
その前に、Turborepo のボイラープレートから不要な部分を取り除くために ui フォルダをクリーンアップしましょう。ui フォルダは以下のようになるはずです:

-ui
  |-src
  |-.eslintrc.js
  |-package.json
  |-tsconfig.json

ここで、pnpm を使用し、ts と Turborepo セットアップを利用しているため、tailwindcss のドキュメントに従って少し修正を加えます。

pnpm --filter ui install -D tailwindcss postcss autoprefixer
cd packages/ui
pnpm dlx tailwindcss init

ドキュメントに従って、postcss.config.js も以下の内容で作成します:

module.exports = {
    plugins: {
      tailwindcss: {},
      autoprefixer: {},
    }
  }

次に、main.css ファイルを以下の内容で作成します:

@tailwind base;
@tailwind components;
@tailwind utilities;

shadcn コンポーネントと utils が機能するようにエイリアスを設定します。shadcn/ui では、コンポーネントが他のコンポーネントと utils をインポートできるようにエイリアスを設定する必要があります。そのために tsconfig.json ファイルを以下のように修正します:

{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
  "baseUrl": ".",
  "paths": {
   "@ui/*": ["./src/*"]
    }
 },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}

ここでは、src ディレクトリを参照するためにエイリアスを使用しています。
次に、shadcn のドキュメントに従ってコンポーネントをセットアップします。以下のコマンドを実行します:

pnpm dlx shadcn-ui@latest init

shadcn/ui はセットアップを完了するためにいくつかの質問をします。私の選択は以下の通りでした:
✔ TypeScript を使用しますか(推奨)? … はい
✔ どのスタイルを使用しますか? › デフォルト
✔ ベースカラーとしてどの色を使用しますか? › Slate
✔ グローバル CSS ファイルはどこにありますか? … main.css
✔ 色に CSS 変数を使用しますか? … はい
✔ カスタム tailwind プレフィックス(例:tw-)を使用していますか?(使用していない場合は空白のままにしてください) …
✔ tailwind.config.js はどこにありますか? … tailwind.config.js
✔ コンポーネントのインポートエイリアスを設定してください: … @ui/components
✔ utils のインポートエイリアスを設定してください: … @ui/lib/utils
✔ React Server Components を使用していますか? … いいえ
✔ components.json に設定を書き込みます。続行しますか? … はい

この時点で、postcss.config.js、tailwind.config.js、あるいは src/lib/utils.ts などのファイルで eslint 関連のエラーが発生している場合、それは tslint.config.json ファイルを削除したにもかかわらず、.eslintrc.js で必要とされているためです。今のところ、該当する行を削除して、新しい .eslintrc.js を以下のようにします:

/**@type {import("eslint").Linter.Config} */
module.exports = {
  root: true,
  extends: ["@repo/eslint-config/react-internal.js"],
  parser: "@typescript-eslint/parser",
};

これが完了したら、以下のコマンドを使用して最初の shadcn コンポーネントを追加しましょう:

pnpm dlx shadcn-ui@latest add button

ヒント💡: ルートの package.json の scripts に "ui:add": "pnpm — filter ui ui:add" を追加すると、上記のコマンドが簡単になります。この追加により、pnpm ui:add [コンポーネント名] を使用して新しいコンポーネントを簡単に追加できます。

また、すべてのコンポーネントをバレルエクスポートするために、ui/src/components に index.ts ファイルを作成します。
現時点では以下のようになります:

export * from "./ui/button";

次に、ui からすべてを適切にエクスポートするために、package.json の exports を以下のように修正します:

"exports": {
  ".": "./src/components/index.ts",
  "./main.css":"./main.css",
  "./postcss.config": "./postcss.config.js",
  "./tailwind.config": "./tailwind.config.js",
  "./lib/*": "./src/lib/*.ts"
 }

これらの手順をすべて完了すると、以下のようなファイル構造になるはずです:

-ui
  |-node_modules
  |-src
  |  |-components
  |  |  |-ui
  |  |  |  |-button.tsx
  |  |  |-index.ts
  |  |-lib
  |  |  |-utils.ts
  |-.eslintrc.js
  |-components.json
  |-main.css
  |-package.json
  |-postcss.config.js
  |-tailwind.config.js
  |-tsconfig.json

ui パッケージの使用

packages/ui での作業が完了したので、apps/vite-project に移動して、実際にボタンコンポーネントを使用します。dependencies 内の package.json に以下の行を追加します:

{
  "dependencies": {
+   "@repo/ui": "workspace:*"
  }
}

また、index.css や App.css などの含まれているすべての css ファイルを削除し、それらのインポート文も削除しましょう。
これで、プロジェクトのルートで pnpm install を実行した後、ボタンコンポーネントを使用する準備が整いました。App.tsx では以下のようになります:

import { Button } from "@repo/ui";
function App() {
  return <Button>MyButton</Button>;
}

export default App;

pnpm run dev を実行すると、ボタンが表示されるはずですが、待ってください!スタイルが適用されていません。以下のコマンドでそれを修正しましょう:

pnpm --filter vite-project install -D tailwindcss postcss autoprefixer
cd apps/vite-project
pnpm dlx tailwindcss init

お気づきかもしれませんが、Turborepo に tailwindcss をインストールして初期化しています。次に、tailwind.config.js を以下のように修正します:

export * from "@repo/ui/tailwind.config"

そして、postcss.config.js を以下のように作成します:

export { default } from "@repo/ui/postcss.config";

これらの変更の後、main.tsx で ui パッケージから main.css ファイルを単純にインクルードします:

import "@repo/ui/main.css";

これらの変更により、ウェブアプリケーションで shadcn のスタイルが適用されたボタンが表示されるはずです。また、tailwindcss を使用して vite+React アプリのレイアウトとスタイルを設定することもできます。

ビルドの問題への対処

最後に、pnpm run build を試みると、エイリアスされたパスを認識できないため tsc がエラーをスローします。これを緩和するために、vite.config.ts で行ったように、tsconfig.json の compilerOptions 内にエイリアスを追加します:

{
  "compilerOptions": {
+    "baseUrl": ".",
+    "paths": {
+     "@ui/*": ["../../packages/ui/src/*"]
+    },
}

これで、アプリの構築が可能になりました。
再度、完全なコードリポジトリはここで確認できます。
読んでいただき、ありがとうございました!


この記事は、2024年2月に弊社のエンジニア Binabh Devkota が執筆した内容を日本語に翻訳したものです。
英語版はこちらをご覧ください。
https://articles.wesionary.team/react-vite-with-shadcn-ui-for-ui-components-all-in-turborepo-8af3deafa58e


採用情報

私たちはプロダクト共創の仕組み化に取り組んでいます。プロダクト共創をリードするプロダクト・マネージャー、そして、私たちのビジョンを市場に届ける営業メンバーを募集しています!


開発パートナーをお探しの企業様へ

弊社は、グローバル開発のメリットを活かし、高い費用対効果と品質を両立しています。経験豊富で多様性のあるチームが、課題を正しく理解し、最適なシステムと優れた体験を実現します。業務システムの開発、新規事業の開発、業務効率化やDX化に関するお困りごと、ぜひ弊社にご相談ください。