In this guide, we will create a monorepo using TurboRepo, integrating React, Express, and PNPM. We will also include shared code for UI components and functions. The process involves several steps. Here’s a detailed guide to help you set up this project:
Step 1: Initialise the Monorepo
1. Install PNPM (if not already installed):
npm install -g pnpm
2. Create the Monorepo Directory:
mkdir turbo-monorepo
cd turbo-monorepo
3. Initialise the Monorepo:
pnpm init
pnpm install -D turbo
4. Setup Turbo Repo Configuration: Create a turbo.json file in the root directory:
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"lint": {},
"test": {}
}
}
Step 2: Setup Workspace and Packages
1. Create Project Directories:
mkdir -p apps/client apps/server packages/ui packages/utils
2. Configure pnpm-workspace.yaml:
packages:
- 'packages/*'
- 'apps/*'
Step 3: Initialise Client (React) and Server (Express) Projects
1. Client (React):
cd apps/client
pnpm create vite . --template react
pnpm install
cd ../..
2. Server (Express):
cd apps/server
pnpm init -y
pnpm add express
touch index.js
cd ../..
3. Add Basic Express Server Code in apps/server/index.js:
import express from "express"
import { greet } from "@shared/utils"
const app = express()
const port = 3000
app.get("/", (req, res) => {
res.send(greet(" This is greeting from common code"))
})
app.listen(port, () => {
console.log(`Server is running at http://localhost:${port}`)
})
Step 4: Add Shared Packages
1. UI Shared Package Setup:
cd packages/ui
pnpm init -y
touch index.js
cd ../..
2. Change Name property of package.json to @shared/ui
{
"name": "@shared/ui",
"version": "1.0.0",
"description": "",
"main": "index.jsx",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
3. Example Shared Component in packages/ui/index.js:
import React from "react"
export const Button = ({ label }) => {
return (
<>
<button type="reset" value="Reset" style={{ background: "red" }}>
{label}
</button>
</>
)
}
1. Setup Shared Utils Package:
cd packages/utils
pnpm init -y
touch index.js
cd ../..
2. Change Name property of package.json to @shared/utils
{
"name": "@shared/utils",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
3. Example Shared Function in packages/utils/index.js:
export const greet = (name) => {
return `Hello, ${name}!`
}
Step 5: Link Shared Packages
Link Packages: (Not sure: This may be not required )
pnpm add @packages/ui @packages/utils --filter @apps/client
pnpm add @packages/utils --filter @apps/server
Step 6: Update package.json Scripts
1. Update Root package.json to add Script and workspace:
Note: Before this install concurrently: pnpm add -D concurrently
{
"name": "turbo-monorepo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"private": true,
"workspaces": [
"apps/*",
"packages/*"
],
"scripts": {
"build": "turbo run build",
"lint": "turbo run lint",
"test": "turbo run test",
"start": "concurrently \"pnpm --filter @apps/server start\" \"pnpm --filter @apps/client dev\""
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"concurrently": "^8.2.2",
"turbo": "^1.13.3"
}
}
2. Update Client to add @shared/utils and @shared/ui in package.json:
{
"name": "@apps/client",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint . --ext js,jsx --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"@shared/utils": "workspace:*",
"@shared/ui": "workspace:*"
},
"devDependencies": {
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
"@vitejs/plugin-react": "^4.2.1",
"vite": "^5.2.0"
}
}
3. Update Server package.json to add @shared/utils dependency
{
"name": "@apps/server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"start": "node index.js",
"lint": "eslint . --ext .js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.19.2",
"@shared/utils": "workspace:*"
}
}
Step 7: Configure ESLint/Prettier/ VSCode Workspace in project root
1. Install ESLint and Prettier:
pnpm add -Dw eslint prettier eslint-plugin-react eslint-config-prettier eslint-plugin-prettier
2. Create ESLint Configuration (.eslintrc.json):
{
"extends": ["eslint:recommended", "plugin:react/recommended", "prettier"],
"plugins": ["react", "prettier"],
"env": {
"browser": true,
"node": true,
"es6": true
},
"parserOptions": {
"ecmaVersion": 2020,
"sourceType": "module"
},
"rules": {
"react/prop-types": "off",
"react/react-in-jsx-scope": "off",
"prettier/prettier": [
"error",
{
"endOfLine": "auto",
"semi": false
}
]
},
"settings": {
"react": {
"version": "detect"
}
}
}
3. Create Prettier Configuration (.prettierrc.json):
{
"singleQuote": false,
"semi": false
}
4. Setup VSCode Workspace : Create .vscode/settings.json:
{
"editor.formatOnSave": true,
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],
"prettier.requireConfig": true
}
Step 8: Start the Applications
Run the start script from the root of the monorepo:
pnpm start
// OR
npm run start
Top comments (0)