Skip to content

Monorepo Setup

IVG-Design edited this page Sep 22, 2025 · 2 revisions

Monorepo Setup

Guide for using DevMirror in monorepo projects with multiple packages.

Automatic Detection

DevMirror automatically detects all package.json files in your workspace:

  1. Open monorepo root in VS Code
  2. DevMirror Scripts panel shows all packages
  3. Each package appears as a collapsible folder
  4. Configure each package independently

Monorepo Structure Support

Lerna

monorepo/
├── package.json           # Root package
├── lerna.json
└── packages/
    ├── app/
    │   └── package.json   # Detected
    ├── lib/
    │   └── package.json   # Detected
    └── cli/
        └── package.json   # Detected

Yarn Workspaces

monorepo/
├── package.json
└── packages/
    ├── frontend/
    │   └── package.json
    ├── backend/
    │   └── package.json
    └── shared/
        └── package.json

PNPM Workspaces

monorepo/
├── package.json
├── pnpm-workspace.yaml
└── apps/
    ├── web/
    │   └── package.json
    └── api/
        └── package.json

Nx

monorepo/
├── package.json
├── nx.json
└── packages/
    └── [packages detected]

Configuration Strategies

1. Package-Level Configuration

Each package has its own config (recommended):

packages/frontend/devmirror.config.json:

{
  "mode": "cdp",
  "url": "http://localhost:3000",
  "outputDir": "../../logs/frontend"
}

2. CEF Application Configuration

For CEF-based applications in monorepo:

packages/backend/devmirror.config.json:

{
  "mode": "cef",
  "cefPort": 8555,
  "outputDir": "../../logs/backend"
}

3. Auto-Detection Configuration

Using auto-detection for varying ports:

packages/app/devmirror.config.json:

{
  "mode": "cdp",
  "autoDetectPort": true,
  "outputDir": "../../logs/app"
}

Port Management

Avoid port conflicts in monorepos:

Sequential URLs

packages/app1/devmirror.config.json:

{
  "mode": "cdp",
  "url": "http://localhost:3000",
  "outputDir": "../../logs/app1"
}

packages/app2/devmirror.config.json:

{
  "mode": "cdp",
  "url": "http://localhost:3001",
  "outputDir": "../../logs/app2"
}

Running Multiple Packages

Concurrent Execution

Root package.json:

{
  "scripts": {
    "dev:all": "lerna run dev:mirror --parallel",
    "dev:apps": "lerna run dev:mirror --scope=@myorg/app-*"
  }
}

With npm workspaces:

{
  "scripts": {
    "dev:all": "npm run dev:mirror --workspaces",
    "dev:frontend": "npm run dev:mirror -w frontend",
    "dev:backend": "npm run dev:mirror -w backend"
  }
}

With yarn workspaces:

{
  "scripts": {
    "dev:all": "yarn workspaces run dev:mirror",
    "dev:frontend": "yarn workspace frontend dev:mirror"
  }
}

With pnpm:

{
  "scripts": {
    "dev:all": "pnpm -r run dev:mirror",
    "dev:apps": "pnpm --filter './apps/**' run dev:mirror"
  }
}

Log Organization

Separate Directories

logs/
├── frontend/
│   ├── 2025-09-22-143052.log
│   └── current.log
├── backend/
│   ├── 2025-09-22-143052.log
│   └── current.log
└── shared/
    └── build.log

Timestamped Folders

logs/
├── 2025-09-22/
│   ├── frontend/
│   ├── backend/
│   └── admin/

Package Prefixes

logs/
├── frontend-2025-09-22-143052.log
├── backend-2025-09-22-143052.log
└── admin-2025-09-22-143052.log

Workspace Scripts

Root-level coordination:

{
  "scripts": {
    "mirror:setup": "node scripts/setup-devmirror.js",
    "mirror:all": "npm run mirror:frontend & npm run mirror:backend",
    "mirror:frontend": "cd packages/frontend && npm run dev:mirror",
    "mirror:backend": "cd packages/backend && npm run dev:mirror",
    "mirror:clean": "rm -rf **/devmirror-logs"
  }
}

VS Code Multi-Root Workspaces

myproject.code-workspace:

{
  "folders": [
    { "path": "packages/frontend" },
    { "path": "packages/backend" },
    { "path": "packages/shared" }
  ],
  "settings": {
    "devmirror.autoRefresh": true,
    "devmirror.autoFold": true
  }
}

Filtering and Scoping

Run specific packages:

# Lerna
lerna run dev:mirror --scope=frontend

# Yarn
yarn workspace frontend dev:mirror

# PNPM
pnpm --filter frontend dev:mirror

# Nx
nx run frontend:dev:mirror

Exclude packages:

Use .gitignore patterns or simply don't add mirror scripts to packages you don't want to mirror.

Cross-Package Communication

Shared configuration helper:

config/devmirror-ports.js:

module.exports = {
  frontend: {
    url: 'http://localhost:3000',
    outputDir: './logs/frontend'
  },
  backend: {
    url: 'http://localhost:8080',
    outputDir: './logs/backend'
  },
  admin: {
    url: 'http://localhost:4000',
    outputDir: './logs/admin'
  }
};

Best Practices

  1. Use consistent port numbering across packages
  2. Centralize log output to monorepo root
  3. Add .gitignore entries for all log directories
  4. Document port assignments in README
  5. Use workspace scripts for coordination
  6. Set up CI/CD to handle multiple packages
  7. Clean logs regularly with workspace scripts

Common Issues

Port conflicts between packages

  • Use sequential port numbers
  • Configure each package with unique ports
  • Use port detection with ranges

Logs scattered across packages

  • Configure central log directory
  • Use consistent outputDir paths
  • Create cleanup scripts

Configuration duplication

  • Use shared base configuration
  • Set defaults at root level
  • Use environment variables

Performance with many packages

  • Run only needed packages
  • Use filtering and scoping
  • Disable unused packages

Example Setup Script

scripts/setup-devmirror.js:

const fs = require('fs');
const path = require('path');

const packages = [
  { name: 'frontend', url: 'http://localhost:3000' },
  { name: 'backend', url: 'http://localhost:8080' },
  { name: 'admin', url: 'http://localhost:4000' }
];

packages.forEach(pkg => {
  const config = {
    mode: 'cdp',
    url: pkg.url,
    outputDir: `../../logs/${pkg.name}`
  };

  const configPath = path.join('packages', pkg.name, 'devmirror.config.json');
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2));

  console.log(`Created config for ${pkg.name}`);
});

Clone this wiki locally