はじめに
本記事では、React、Express、GraphQL、Turborepoを使って、モノレポ環境を構築し、効率的な開発環境を整える方法について解説します。モノレポ構成の利点を活かし、複数のプロジェクトを1つのリポジトリで管理することで、依存関係の管理やビルド時間の短縮、開発のスピードアップが可能になります。Turborepoを活用しフロントエンドとバックエンドを効率的に開発できるセットアップを一緒に学んでいきましょう。
今回のゴール
フロントエンドであるReactとバックエンドであるExpressを1つのリポジトリにセットアップし、turborepo
を使ってまとめて起動できるようにします。
その後、ReactからExpressにアクセスできることを確認します。
ディレクトリ構成が初見では複雑に見えますので詳しい解説も載せています。
.
├── apps
│ ├── backend
│ │ ├── src
│ │ │ └── index.ts
│ │ ├── package.json
│ │ └── tsconfig.json
│ └── frontend
│ ├── dist
│ │ ├── assets
│ │ │ ├── index-D5Y6grW-.js
│ │ │ └── index-kQJbKSsj.css
│ │ ├── index.html
│ │ └── vite.svg
│ ├── public
│ │ └── vite.svg
│ ├── src
│ │ ├── assets
│ │ │ └── react.svg
│ │ ├── App.tsx
│ │ ├── main.tsx
│ │ └── vite-env.d.ts
│ ├── .gitignore
│ ├── README.md
│ ├── eslint.config.js
│ ├── index.html
│ ├── package.json
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
├── package-lock.json
├── package.json
└── turbo.json
Turborepoとは
Turborepo(ターボレポ)は、モノレポ(monorepo)構成を管理するためのツールで、主にJavaScriptやTypeScriptのプロジェクトに利用されます。モノレポとは、複数のプロジェクトやパッケージを一つのリポジトリ内で管理するアプローチです。Turborepoは、このようなモノレポを効率的に扱うためのツールです。
Turborepoの主な特徴
-
ビルドパイプラインの高速化: Turborepoは、依存関係の管理を効率化するため、インクリメンタルビルドをサポートします。変更された部分のみを再ビルドすることで、ビルド時間を短縮し、開発を加速します。
-
キャッシュ機能: ビルド結果をキャッシュすることで、同じ処理を何度も行わずに済みます。これにより、CI/CDやローカル開発環境でのビルドが高速化されます。
-
依存関係の管理: モノレポ内の複数のパッケージ間での依存関係を効率よく管理できます。Turborepoは、タスクやスクリプトが依存するパッケージ間で自動的に適切な順序で処理を実行します。
-
分散型タスク実行: 複数のパッケージが存在する場合でも、Turborepoは並列にタスクを実行して、開発のスピードを向上させます。
-
簡単な設定: Turborepoは、turbo.jsonという設定ファイルを用いてプロジェクトの設定を簡単に管理できます。また、npmやpnpm、yarnなどのパッケージマネージャーと統合されており、標準的なツールチェインと共に動作します。
-
CI/CDサポート: Turborepoは、CI/CDパイプラインを効率的に設定できるようサポートします。変更のあった部分だけをビルドし、無駄な作業を省けます。
セットアップ
まずは全体のプロジェクトのセットアップから始めます。
mkdir Documents/workspace/react-express-graphql-turborepo
cd Documents/workspace/react-express-graphql-turborepo
npm init -y
Turborepo
を使えるようインストールします。
npm install turbo -D
次にTurborepo
の設定を行います。
タスクという形でビルドや開発モードでの起動などの設定ができます。
{
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
dev
で起動する時は基本的に長時間実行されるもので"persistent": true
を入れることでreact
とexpress
の双方が他タスクに影響を与えて中断されないようにしています。
次にルート直下のpackage.jsonの修正をします。
{
"name": "react-express-graphql-turborepo",
+ "workspaces": ["apps/*", "packages/*"],
"version": "1.0.0",
"description": "",
- "main": "index.js",
+ "packageManager": "npm@10.9.2",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"turbo": "^2.4.0"
}
}
package.jsonのworkspacesは、モノレポ(monorepo)を構築するための設定です。モノレポとは、複数のパッケージやアプリケーションを単一のリポジトリ内で管理するアプローチです。
workspacesを使用すると、異なるパッケージ(アプリケーションやライブラリ)を同じリポジトリ内で効率的に管理でき、依存関係の共有やインストールの高速化、開発の効率化ができます。
以上でルート直下での初期設定は終了となります。
フロントエンド(React + Vite)の作成
ここから個別のアプリケーションの設定となります。
まずはフロントエンドから設定してきます。
mkdir apps
cd apps
npm create vite@latest frontend
{
- "name": "frontend",
+ "name": "@react-express-graphql-turborepo/frontend",
"private": true,
スコープ付きパッケージの設定をします。
今回の記事ではまだあまり重要ではありませんが一旦設定しておきます。
ViteとReactの必要なファイルをダウンロードできたのでパッケージをインストールします。
cd apps/frontend
npm install
インストールが終わったら念のため起動し動作確認をしておきます。
npm run dev
下記のように表示され、http://localhost:5173/
にアクセスできればOKです。
VITE v6.1.0 ready in 319 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
➜ press h + enter to show help
以上でVite + Reactによるフロントエンドの設定は終了です。
今回はモノレポ構成についてがメインとなるためViteやReactについての記載は最小限にしていますが、これらのツールについて詳しく知りたい方はこちらの記事もご参考ください。
バックエンド(Experss)の作成
次にバックエンドとしてExpressの設定を行います。
まずはパッケージのインストールを行います。
mkdir apps/backend && cd apps/backend
npm init -y
npm i express cors dotenv
npm i -D typescript ts-node @types/node @types/express @types/cors
その後、スコープ付きパッケージの設定、tsconfig.json
の設定を行います。
{
- "name": "backend",
+ "name": "@react-express-graphql-turborepo/backend",
"version": "1.0.0",
{
"compilerOptions": {
"outDir": "dist",
"rootDir": "src",
"strict": true,
"module": "CommonJS",
"target": "ES6",
"esModuleInterop": true
}
}
Express
を動かせる環境ができましたら実際に起動するファイルを作成します。
import express from "express";
import cors from "cors";
const app = express();
const PORT = process.env.PORT || 4000;
app.use(cors());
app.use(express.json());
app.get("/", (req, res) => {
res.send("Hello from Express!");
});
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
まずはhttps://localhost:4000
でアクセスすると、Hello from Express!
と返ってくるようにしました。
ファイルが作成できましたら、package.json
で起動する処理を定義します。
- "main": "index.js",
+ "main": "index.ts",
"scripts": {
+ "dev": "ts-node src/index.ts",
"test": "echo \"Error: no test specified\" && exit 1"
},
念のためExpress
が起動できるか確認します。
npm run dev
Server is running on http://localhost:4000
起動できましたら、curl
でレスポンスを確認します。
curl http://localhost:4000
Hello from Express!
以上でExperss
のセットアップは終了となります。
こちらについてもExpressの記載は最小限にしていますが、詳しく知りたい方はこちらの記事もご参考ください。
フロントエンドからバックエンドにアクセス
fetch
モジュールを使って先ほど返ってきたHello from Express!
をブラウザで表示させます。
import { useEffect, useState } from "react";
function App() {
const [message, setMessage] = useState("");
useEffect(() => {
fetch("http://localhost:4000")
.then((res) => res.text())
.then((data) => setMessage(data));
}, []);
return (
<div>
<h1>React + Express</h1>
<p>API Response: {message}</p>
</div>
);
}
export default App;
初期設定のCSSが残って影響を与えるので一旦削除します。
rm apps/frontend/src/index.css
rm apps/frontend/src/App.css
またcssを読み込んでいるファイルも修正しておきます。
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
- import './index.css'
import App from './App.tsx'
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
)
一通り設定ができましたのでReactとExpressをTurborepoから起動します。
ルート直下で下記コマンドを実行します。
npm run dev
起動でき、APIのレスポンスがブラウザに表示されることを確認します。
ディレクトリ構成について
基本的にはapps
配下がメインとなります。
今回はfrontend
, backend
という2つのディレクトリを用意してそれぞれ管理する形としました。
tree -I node_modules -I .git -I .turbo --dirsfirst -a
.
├── apps
│ ├── backend
│ │ ├── src
│ │ │ └── index.ts
│ │ ├── package.json
│ │ └── tsconfig.json
│ └── frontend
│ ├── dist
│ │ ├── assets
│ │ │ ├── index-D5Y6grW-.js
│ │ │ └── index-kQJbKSsj.css
│ │ ├── index.html
│ │ └── vite.svg
│ ├── public
│ │ └── vite.svg
│ ├── src
│ │ ├── assets
│ │ │ └── react.svg
│ │ ├── App.tsx
│ │ ├── main.tsx
│ │ └── vite-env.d.ts
│ ├── .gitignore
│ ├── README.md
│ ├── eslint.config.js
│ ├── index.html
│ ├── package.json
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
├── package-lock.json
├── package.json
└── turbo.json
トップレベルのディレクトリ
.
├── package-lock.json
├── package.json
├── turbo.json
- package.json
- モノレポ全体のルート package.json
- apps/backend や apps/frontend の依存関係を統合管理する
- workspace の設定
- package-lock.json
- インストールされた依存関係のバージョンが固定されるファイル
- npm install を実行すると自動生成される
- turbo.json
- Turborepo の設定ファイル
- どのパッケージを
apps
に含めるか、どのスクリプトを並列/キャッシュ実行するかを定義
アプリケーションのディレクトリ (apps/)
├── apps
│ ├── backend
│ └── frontend
- apps/ 内に backend (Express) と frontend (React + Vite) が分かれている
- モノレポの標準的なディレクトリ構造
backend
とfrontend
をそれぞれ 独立したプロジェクトとして管理
バックエンド (apps/backend/)
│ ├── backend
│ │ ├── src
│ │ │ └── index.ts
│ │ ├── package.json
│ │ └── tsconfig.json
- src/index.ts
- Express のエントリーポイント
- サーバーを起動するメインファイル
- package.json
- バックエンドの 依存関係やスクリプト を管理
フロントエンド (apps/frontend/)
│ └── frontend
│ ├── dist
│ │ ├── assets
│ │ │ ├── index-D5Y6grW-.js
│ │ │ └── index-kQJbKSsj.css
│ │ ├── index.html
│ │ └── vite.svg
│ ├── public
│ │ └── vite.svg
│ ├── src
│ │ ├── assets
│ │ │ └── react.svg
│ │ ├── App.tsx
│ │ ├── main.tsx
│ │ └── vite-env.d.ts
│ ├── .gitignore
│ ├── README.md
│ ├── eslint.config.js
│ ├── index.html
│ ├── package.json
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
- dist/
- Vite でビルドされたファイルが格納される
assets/
に JS, CSS, 画像などのビルド成果物 が入る
- public/
- 静的ファイル を格納
vite.svg
は Vite のデフォルトアイコンpublic/
のファイルはdist/
にコピーされる
- src/
- フロントエンドのソースコード
- vite.config.ts
Vite
の設定ファイルReact
プラグインやalias
設定を記述
さいごに
この記事を通じて、Turborepoを使用したモノレポ構成の基本的なセットアップ方法と、React + ViteのフロントエンドとExpressのバックエンドを統合する方法を学んでいただけたことと思います。このような構成により、複数のアプリケーションを効率よく管理し、ビルドの高速化や依存関係の管理が簡単に行えるようになります。これからモノレポを使った開発環境を整備する際の参考にしていただければ幸いです。Turborepoを使うことで、開発の生産性を大幅に向上させることができますので、ぜひ実際のプロジェクトに取り入れてみてください。
関連する技術ブログ
React × Tailwind CSS × Emotionで実践するコンポーネント設計ガイド:デザインシステム・状態管理・再利用性の最適解
React、Tailwind CSS、Emotion、Storybook、Figma、Next.jsを活用したコンポーネント設計のベストプラクティスを紹介。デザインシステムに基づく命名規則、適切な状態管理、再利用性を高める抽象化、アクセシビリティ対応、スタイルガイドラインの整備、テーマ設定、バージョン管理、ドキュメント作成まで、モダンフロントエンド開発に欠かせない知識を徹底解説します。
shinagawa-web.com
NestJS × React × Railway:ブログUIを実装して本番環境へデプロイ
NestJS+React+Prismaで構成したブログアプリを、Dockerで本番ビルドし、クラウドサービス「Railway」へデプロイするまでの手順をまとめました。本番DB接続、環境変数管理、フロントエンドとバックエンドの統合配信など、運用を意識した実践的な構成に仕上げていきます。個人開発やPoCにも応用できる「即戦力の本番構成」を一緒に組み立てていきましょう。
shinagawa-web.com
スキーマ駆動開発の実践:React × Express × GraphQLで効率的なAPI設計を実現
GraphQLを活用したスキーマ駆動開発(Schema-Driven Development, SDD)の実践方法を解説します。React(フロントエンド)とExpress(バックエンド)を組み合わせ、GraphQLスキーマを基にAPI設計を進めることで、型安全性と開発効率を向上させる手法を紹介します。GraphQL Code Generatorを用いた型定義の自動生成、スキーマ設計のベストプラクティス、Turborepoによるモノレポ構成についても詳しく解説します。
shinagawa-web.com
WebpackでReactとTypeScriptをセットアップするステップガイド
ReactとTypeScriptを使ったアプリケーション開発を、Webpackを使って効率的にセットアップする方法を詳しく解説します。バンドル環境の構築から、実際の開発まで役立つステップを紹介します。
shinagawa-web.com
GraphQL・REST API の堅牢な認可設計:RBAC・ABAC・OAuth 2.0 のベストプラクティス
GraphQL & REST API の堅牢な認可設計を構築する方法とは?RBAC・ABAC の活用、Rate Limiting、API Gateway、監視のベストプラクティスをまとめました。
shinagawa-web.com
ExpressとMongoDBで簡単にWeb APIを構築する方法【TypeScript対応】
本記事では、MongoDB Atlasを活用してREST APIを構築する方法を、初心者の方にも分かりやすいステップで解説します。プロジェクトの初期設定からMongoDBの接続設定、Expressを使用したルートの作成、さらにTypeScriptを用いた型安全な実装まで、実践的なサンプルコードを交えて丁寧に説明します。
shinagawa-web.com
Express(+TypeScript)入門ガイド: Webアプリケーションを素早く構築する方法
Node.jsでWebアプリケーションを構築するための軽量フレームワーク、Expressの基本的な使い方を解説。シンプルなサーバー設定からルーティング、ミドルウェアの活用方法、TypeScriptでの開発環境構築まで、実践的なコード例とともに学べます。
shinagawa-web.com
マイクロサービス戦略の実践:BFF・API管理・認証基盤を支える技術スタック(AWS, Keycloak, gRPC, Kafka)
マイクロサービス化を進める上で、適切なアーキテクチャ設計と技術選定が重要です。本記事では、BFF の導入計画、API Gateway を活用したエンドポイント管理、認証・認可の統合、非同期メッセージング、サービス間通信の最適化 など、多岐にわたるトピックを解説します。サンプルとして、AWS の活用例、Keycloak による認証基盤の整備、gRPC を用いた高速通信、Kafka & RabbitMQ によるメッセージング、Swagger での API ドキュメント標準化 などを紹介。マイクロサービスを支える技術スタックとその実践的な活用方法を学びたい方におすすめの内容です。
shinagawa-web.com