6.9 KiB
Development Guide
This monorepo uses Turborepo to manage builds, development, and testing across multiple packages and applications.
Repository Structure
xtablo-source/
├── apps/
│ ├── main/ # Main application (@xtablo/main)
│ └── external/ # External application (@xtablo/external)
├── packages/
│ ├── shared/ # Shared utilities and logic (@xtablo/shared)
│ └── ui/ # UI component library (@xtablo/ui)
Prerequisites
- Node.js >= 18
- pnpm >= 10.19.0
Getting Started
# Install dependencies
pnpm install
# Start development (packages are source-only, no build needed)
pnpm dev
Available Commands
Building
# Build all apps (packages are source-only, consumed directly by bundlers)
pnpm build
# Build only apps (main, external)
pnpm build:apps
# Build main app for specific environments
pnpm build:staging # Build for staging
pnpm build:prod # Build for production
Note: The @xtablo/shared and @xtablo/ui packages are source-only packages. They export TypeScript source files directly and are consumed by app bundlers (Vite) without a separate build step. This is faster and simpler for development.
Environment Builds: The main app supports environment-specific builds (staging, production) that are properly cached by Turborepo based on environment-specific inputs (.env.staging, .env.production, etc.).
Development
# Run all apps in development mode
pnpm dev
# Run specific app
pnpm dev:main # Main app only
pnpm dev:external # External app only
Note: Since packages are source-only, there's no need to run them in watch mode. Changes to package files are instantly picked up by the app's bundler (Vite) through hot module replacement.
Testing
# Run all tests
pnpm test
# Run tests in watch mode
pnpm test:watch
# Run tests for specific package
cd apps/main && pnpm test
cd apps/main && pnpm test:watch
cd apps/main && pnpm test:coverage
Linting & Formatting
# Check all packages
pnpm lint
# Fix linting issues
pnpm lint:fix
# Format code
pnpm format
# Type checking
pnpm typecheck
Cleaning
# Clean all build artifacts
pnpm clean
# Clean specific app
cd apps/main && pnpm clean
Turborepo Features
Smart Caching
Turborepo caches build outputs and skips unnecessary work:
- Build outputs are cached based on input files
- If nothing changed, builds are instant
- Cache is shared across the team (when configured)
Parallel Execution
Tasks run in parallel when possible:
# Runs lint on all packages simultaneously
pnpm lint
Task Dependencies
Turborepo automatically handles task dependencies:
builddepends on^build(builds dependencies first, though packages are source-only)- Tasks run in topological order based on package dependencies
Filtering
Run commands for specific packages:
# Build only main app and its dependencies
turbo build --filter=@xtablo/main
# Build only packages
turbo build --filter='./packages/*'
# Build everything except external
turbo build --filter='!@xtablo/external'
Package-Level Configuration
Packages can have their own turbo.json file to define custom tasks or override root configuration:
Example: apps/main/turbo.json defines environment-specific builds:
build:staging- Builds for staging with.env.stagingbuild:prod- Builds for production with.env.production
Each task:
- Extends the root config with
"extends": ["//"] - Defines specific inputs (including environment files)
- Configures caching with appropriate outputs
- Can pass environment variables to the build process
Package Development Workflow
1. Working on Packages
Since packages are source-only, just run your app and edit package files directly:
# Just run your app - changes to packages are instantly reflected
pnpm dev:main
# Or run all apps
pnpm dev
The app's bundler (Vite) will automatically detect changes in packages/shared and packages/ui and hot-reload them.
2. Adding a New Package
- Create the package in
packages/ - For source-only packages (like shared/ui), add these scripts to
package.json:{ "scripts": { "lint": "biome check .", "lint:fix": "biome check --write .", "format": "biome format --write .", "typecheck": "tsc --noEmit" } } - Set up exports in
package.json:{ "main": "./src/index.ts", "types": "./src/index.ts", "exports": { ".": "./src/index.ts" } } - Add to workspace in
pnpm-workspace.yaml(if not already included by glob) - Run
pnpm installto link the package
3. Testing Changes Across Packages
When making changes that affect multiple packages:
# Type check everything
pnpm typecheck
# Run all tests
pnpm test
# Lint everything
pnpm lint
Performance Tips
- Source-Only Packages: Packages consume TypeScript directly for instant feedback
- Selective Builds: Use filters to build only the apps you need
- Clean When Stuck: Run
pnpm cleanif you encounter weird caching issues - Hot Module Replacement: Vite provides instant updates when editing package files
Troubleshooting
Build Errors
If you encounter build errors:
# Clean everything and rebuild
pnpm clean
pnpm install
pnpm build
Type Errors in Apps
If apps show type errors for packages:
# Check TypeScript configuration in packages
cd packages/shared && pnpm typecheck
cd packages/ui && pnpm typecheck
# Restart your IDE's TypeScript server
# In VS Code: Cmd+Shift+P > "TypeScript: Restart TS Server"
Cache Issues
If builds seem stale:
# Clear Turbo cache
rm -rf node_modules/.cache/turbo
# Clean and rebuild
pnpm clean
pnpm build
CI/CD Considerations
Basic Pipeline
For CI/CD pipelines:
# Install dependencies
pnpm install --frozen-lockfile
# Build everything
pnpm build
# Run all checks
pnpm lint
pnpm typecheck
pnpm test
Environment-Specific Deployments
Staging Pipeline:
# Install dependencies
pnpm install --frozen-lockfile
# Build for staging
pnpm build:staging
# Deploy (example with wrangler)
cd apps/main && pnpm deploy:staging
Production Pipeline:
# Install dependencies
pnpm install --frozen-lockfile
# Run all checks
pnpm lint
pnpm typecheck
pnpm test
# Build for production
pnpm build:prod
# Deploy (example with wrangler)
cd apps/main && pnpm deploy:prod
Benefits:
- Turborepo caches builds per environment
- Environment-specific
.envfiles are tracked as inputs - Builds are only re-run when relevant files change