@presetter/preset-monorepo
Introduced in v8.0.0 - A comprehensive preset designed specifically for TypeScript monorepos with intelligent workspace management and unified tooling. Updated in v8.3 with broader linting and workspace test discovery.
Purposeโ
This preset solves the "monorepo configuration hell" problem by providing:
- ๐๏ธ Zero configuration duplication across packages
- ๐งช Unified testing with workspace-based test running
- ๐ Type-safe monorepo with TypeScript project references
- โก Instant package setup - new packages work immediately
- ๐ Always synchronized configurations across the entire workspace
Key Featuresโ
Context-Aware Configurationโ
The preset intelligently adapts based on where it's applied:
- Repository Root: Generates workspace-level configurations with project references
- Individual Packages: Minimal configuration that inherits from root
Unified Toolingโ
Built on top of two powerful presets:
@presetter/preset-esm- Modern ES modules configuration@presetter/preset-strict- Enhanced linting and type safety
Workspace Testingโ
Aggregated test running across all packages with:
- Unified coverage reporting
- Multi-format output (text, HTML, JSON, LCOV)
- 100% coverage thresholds
- Intelligent test discovery
Installationโ
Repository Setupโ
# Install at repository root
npm install --save-dev presetter @presetter/preset-monorepo
# Create configuration
echo "export { default } from '@presetter/preset-monorepo';" > presetter.config.ts
# Bootstrap entire monorepo
npx presetter bootstrap --projects . --projects packages/*/
Package Manager Integrationโ
Works seamlessly with all major package managers:
# npm workspaces
npm install --save-dev presetter @presetter/preset-monorepo
# pnpm workspaces
pnpm add -D presetter @presetter/preset-monorepo
# yarn workspaces
yarn add --dev presetter @presetter/preset-monorepo
Configurationโ
Basic Setupโ
// Simple monorepo configuration
export { default } from '@presetter/preset-monorepo';
Advanced Customizationโ
import monorepo from '@presetter/preset-monorepo';
export default {
...monorepo,
// Override test patterns
override: {
'vitest.config.ts': {
test: {
workspace: [
'packages/*/vitest.config.ts',
'apps/*/vitest.config.ts',
],
coverage: {
thresholds: {
global: {
branches: 90, // Relax from 100%
functions: 95,
lines: 95,
statements: 95,
},
},
},
},
},
},
};
Real-World Configuration (Root vs Package Overrides)โ
This pattern is used in production monorepos to apply different overrides at the repo root vs. individual packages:
import { asset, preset } from 'presetter';
import monorepo from '@presetter/preset-monorepo';
import type { ViteUserConfig } from 'vitest/config';
export default preset('my-org', {
extends: [monorepo],
variables: {
target: 'ES2024',
},
override: {
assets: (context) =>
context.isRepoRoot
? {
'.gitignore': ['.notes', '.drafts'],
'vitest.config.ts': asset<{ default: ViteUserConfig }>((current) => ({
...current,
default: {
...current?.default,
test: {
...current?.default?.test,
projects: ['*/*/vitest.config{,.int,.e2e}.ts'],
},
},
})),
}
: {
'eslint.config.ts': {
default: [
{
name: 'monorepo:override',
rules: {
'max-lines': 'off',
},
},
],
},
},
},
});
Package-Level Customizationโ
import base from '../../presetter.config.ts';
export default {
...base,
// Package-specific overrides
override: {
'vitest.config.ts': {
test: {
// Package-specific test configuration
setupFiles: ['./test/setup.ts'],
environment: 'jsdom', // For packages that need DOM
},
},
},
};
Generated Filesโ
Repository Rootโ
When applied to the monorepo root, generates:
eslint.config.tsโ
// Monorepo-wide linting configuration
export default [
{
ignores: [
'**/lib/**', // Build outputs
'**/types/**', // Generated types
'**/generated/**', // Generated files
'**/node_modules/**',
],
},
// ... ESLint rules from preset-strict
];
tsconfig.jsonโ
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "bundler",
"target": "ES2022",
"baseUrl": "."
},
"files": [],
"references": [] // Manually add package references
}
vitest.config.tsโ
// Workspace test runner
export default defineConfig({
test: {
workspace: ['*/*/vitest.config{,.int,.e2e}.ts'],
coverage: {
thresholds: {
global: {
branches: 100,
functions: 100,
lines: 100,
statements: 100,
},
},
reporter: ['text', 'html', 'clover', 'json', 'lcov'],
excludeAfterRemap: true,
},
},
});
Individual Packagesโ
For packages, generates minimal configuration that inherits from root:
- Removes
.prettierrc.json(uses root configuration) - Inherits all other configurations from base presets
- Maintains package-specific
package.jsonscripts
Usage Examplesโ
Development Workflowโ
# Root level - affects entire monorepo
npm run typecheck # Check types across all packages
npm run lint # Lint and format entire workspace
npm run test # Run all tests with unified coverage
# Package level
cd packages/my-package
npm run build # Build this package
npm run test:watch # Watch tests for this package
Testing Strategyโ
# Run all tests
npm run test
# Run tests for specific packages
npm run test -- packages/core
# Run with coverage
npm run test:coverage
# Integration tests only
npm run test:int
# End-to-end tests only
npm run test:e2e
CI/CD Integrationโ
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18
cache: 'npm'
- run: npm ci
- run: npm run bootstrap
- run: npm run typecheck
- run: npm run lint
- run: npm run test
- run: npm run build
Best Practicesโ
Repository Structureโ
my-monorepo/
โโโ packages/
โ โโโ core/ # Core package
โ โโโ utils/ # Utility package
โ โโโ components/ # UI components
โโโ apps/
โ โโโ web/ # Web application
โ โโโ api/ # API server
โโโ tools/
โ โโโ build-config/ # Shared build tools
โโโ presetter.config.ts
โโโ package.json
โโโ tsconfig.json
TypeScript Project Referencesโ
Manually configure TypeScript project references for optimal type checking:
{
"files": [],
"references": [
{ "path": "./packages/core" },
{ "path": "./packages/utils" },
{ "path": "./packages/components" },
{ "path": "./apps/web" },
{ "path": "./apps/api" }
]
}
Package Dependenciesโ
Establish clear dependency hierarchies:
{
"dependencies": {
"@my-org/core": "workspace:*",
"@my-org/utils": "workspace:*"
}
}
Test Organizationโ
Organize tests by type across the workspace:
packages/core/
โโโ src/
โ โโโ index.ts
โโโ spec/
โ โโโ unit/ # Unit tests
โ โโโ integration/ # Integration tests
โ โโโ e2e/ # End-to-end tests
โโโ vitest.config.ts # Package test config
โโโ package.json
Variablesโ
Inherits configuration variables from @presetter/preset-esm:
| Variable | Default | Description |
|---|---|---|
source | "src" | Source code directory |
output | "lib" | Build output directory |
test | "spec" | Test files directory |
types | "types" | TypeScript declarations |
generated | "generated" | Generated files directory |
target | "ES2022" | TypeScript compilation target |
Troubleshootingโ
Issue: Package not found in workspaceโ
Problem: New package not detected by workspace tools
Solution: Re-run bootstrap to include new packages:
npx presetter bootstrap --projects . --projects packages/*/
Issue: Type errors across packagesโ
Problem: TypeScript can't resolve cross-package types
Solution: Add package references to root tsconfig.json:
{
"references": [
{ "path": "./packages/new-package" }
]
}
Issue: Test coverage issuesโ
Problem: Coverage reporting incorrect for workspace
Solution: Ensure all packages have proper test configurations:
# Verify workspace test pattern
npm run test -- --reporter=verbose
Issue: Linting configuration conflictsโ
Problem: Individual packages have conflicting ESLint rules
Solution: Remove package-level ESLint configs and use workspace configuration:
# Remove conflicting configs
find packages -name "eslint.config.*" -delete
find packages -name ".eslintrc.*" -delete
Migration from Other Setupsโ
From Lernaโ
# Remove Lerna configuration
rm lerna.json
# Install preset-monorepo
npm install --save-dev presetter @presetter/preset-monorepo
# Bootstrap workspace
npx presetter bootstrap --projects . --projects packages/*/
From Nxโ
# Remove Nx configuration
rm -rf nx.json .nxignore tools/
# Install preset-monorepo
npm install --save-dev presetter @presetter/preset-monorepo
# Adapt workspace structure
npx presetter bootstrap --projects . --projects packages/*/
From Manual Setupโ
# Clean existing configurations
find . -name "tsconfig.json" -not -path "./node_modules/*" -delete
find . -name "eslint.config.*" -not -path "./node_modules/*" -delete
find . -name "vitest.config.*" -not -path "./node_modules/*" -delete
# Install and bootstrap
npm install --save-dev presetter @presetter/preset-monorepo
npx presetter bootstrap --projects . --projects packages/*/
Next Stepsโ
- New packages: Simply create package directory and re-run bootstrap
- Custom configurations: Use the override system for package-specific needs
- Advanced features: Explore preset composition for complex requirements
- Performance: Consider incremental builds and selective testing for large workspaces
The preset-monorepo is perfect for teams managing complex TypeScript monorepos who want unified tooling without configuration overhead.