Налаштування Monorepo (Turborepo) для веб-проекту

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.
Розробка та обслуговування будь-яких видів сайтів:
Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Налаштування Monorepo (Turborepo) для веб-проекту
Складна
~3-5 робочих днів
Часті питання
Наші компетенції:
Етапи розробки
Останні роботи
  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Налаштування Monorepo (Turborepo) для веб-проекту

Turborepo — build system для monorepo від Vercel. Не менеджер пакетів та не лінтер — саме інструмент для розумного запуску завдань з кешуванням результатів. Головна ідея: якщо вхідні файли завдання не змінилися, вихід береться з кешу. На практиці це означає turbo build за 3 секунди замість 4 хвилин при повторному запуску.

Коли Turborepo, а не просто npm workspaces

npm/yarn/pnpm workspaces вже дають monorepo-структуру з загальними залежностями. Turborepo додає поверх них:

  • Паралельний запуск з урахуванням залежностей між пакетами
  • Інкрементальний кеш (локальний + віддалений)
  • Граф завдань з явними залежностями
  • Фільтрацію: запустити лише змінені пакети

Якщо проект невеликий (2–3 пакети) та команда маленька — workspaces без Turbo достатньо. При 5+ пакетах та CI/CD — Turbo починає економити реальний час.

Структура проекту

my-project/
├── apps/
│   ├── web/                 # Next.js фронтенд
│   ├── admin/               # Vite + React admin panel
│   └── api/                 # Node.js/Express backend
├── packages/
│   ├── ui/                  # загальні React-компоненти
│   ├── config/
│   │   ├── eslint/          # конфіг ESLint
│   │   ├── typescript/      # базові tsconfig
│   │   └── tailwind/        # tailwind preset
│   ├── utils/               # загальні утиліти (formatDate, тощо)
│   └── types/               # загальні TypeScript-типи
├── package.json             # оголошення workspaces
├── turbo.json               # конфігурація Turborepo
└── pnpm-workspace.yaml      # якщо використовуємо pnpm

Інініціалізація

# Створюємо новий monorepo
npx create-turbo@latest my-project
cd my-project

# Або додаємо Turbo у існуючий проект
pnpm add turbo --save-dev --workspace-root

Конфігурація turbo.json

{
  "$schema": "https://turbo.build/schema.json",
  "globalDependencies": [".env"],
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "inputs": ["src/**", "package.json", "tsconfig.json"],
      "outputs": ["dist/**", ".next/**", "!.next/cache/**"],
      "env": ["NODE_ENV", "API_URL"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    },
    "lint": {
      "inputs": ["src/**", "*.ts", "*.tsx", ".eslintrc*"],
      "outputs": []
    },
    "typecheck": {
      "dependsOn": ["^build"],
      "inputs": ["src/**", "tsconfig.json"],
      "outputs": []
    },
    "test": {
      "dependsOn": ["^build"],
      "inputs": ["src/**", "test/**", "vitest.config.*"],
      "outputs": ["coverage/**"],
      "env": ["TEST_DATABASE_URL"]
    },
    "test:e2e": {
      "dependsOn": ["build"],
      "inputs": ["e2e/**", "playwright.config.*"],
      "outputs": ["test-results/**"],
      "cache": false
    },
    "db:generate": {
      "cache": false,
      "inputs": ["prisma/schema.prisma"]
    }
  }
}

^build означає «спочатку зібрати всі залежності цього пакета». Turbo автоматично визначає порядок: packages/ui зберуться до apps/web, тому що web залежить від ui.

Налаштування пакетів

// packages/ui/package.json
{
  "name": "@acme/ui",
  "version": "0.0.0",
  "private": true,
  "exports": {
    ".": {
      "import": "./dist/index.js",
      "types": "./dist/index.d.ts"
    },
    "./styles": "./dist/styles.css"
  },
  "scripts": {
    "build": "tsup src/index.ts --format esm --dts",
    "dev": "tsup src/index.ts --format esm --dts --watch",
    "lint": "eslint src/",
    "typecheck": "tsc --noEmit"
  },
  "devDependencies": {
    "@acme/eslint-config": "*",
    "@acme/typescript-config": "*",
    "tsup": "^8.0.0"
  },
  "peerDependencies": {
    "react": "^18.0.0"
  }
}
// apps/web/package.json
{
  "name": "@acme/web",
  "private": true,
  "dependencies": {
    "@acme/ui": "*",
    "@acme/utils": "*"
  }
}

"*" — workspace-протокол: pnpm/yarn розв'яжуть у локальний пакет. У npm потрібно вказувати "workspace:*" явно.

Спільний TypeScript конфіг

// packages/config/typescript/base.json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "lib": ["ES2020"],
    "skipLibCheck": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  }
}

// packages/config/typescript/react.json
{
  "extends": "./base.json",
  "compilerOptions": {
    "jsx": "react-jsx",
    "lib": ["ES2020", "DOM", "DOM.Iterable"]
  }
}

// apps/web/tsconfig.json
{
  "extends": "@acme/typescript-config/react.json",
  "compilerOptions": {
    "baseUrl": ".",
    "paths": { "@/*": ["./src/*"] }
  },
  "include": ["src", "next-env.d.ts"]
}

Віддалений кеш

Локальний кеш працює лише на одній машині. Для команди та CI потрібен remote cache. Vercel Remote Cache — безплатно для open source, платно для приватних:

# Авторизація (один раз)
npx turbo login
npx turbo link

# Або self-hosted через ducktape/turborepo-remote-cache

Варіант self-hosted через turborepo-remote-cache (відкритий сервер):

# docker-compose.yml для сервера remote cache
services:
  turbo-cache:
    image: ducktors/turborepo-remote-cache:latest
    ports:
      - "3000:3000"
    environment:
      TURBO_TOKEN: "your-secret-token"
      STORAGE_PROVIDER: "s3"
      S3_BUCKET: "turbo-cache-bucket"
      AWS_ACCESS_KEY_ID: "${AWS_ACCESS_KEY_ID}"
      AWS_SECRET_ACCESS_KEY: "${AWS_SECRET_ACCESS_KEY}"
// turbo.json — endpoint remote cache
{
  "remoteCache": {
    "signature": true
  }
}
# Запуск з remote cache
TURBO_TOKEN=your-secret-token TURBO_API=https://cache.internal.example.com \
  turbo build

CI/CD з Turborepo

# .github/workflows/ci.yml
name: CI
on: [push, pull_request]

jobs:
  ci:
    runs-on: ubuntu-latest
    env:
      TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
      TURBO_TEAM: ${{ secrets.TURBO_TEAM }}

    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 2  # потрібно для --filter=...[HEAD^1]

      - uses: pnpm/action-setup@v3
        with:
          version: 9

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: pnpm

      - run: pnpm install --frozen-lockfile

      # Запускаємо лише завдання для змінених пакетів
      - run: pnpm turbo lint typecheck test --filter=...[HEAD^1]

      # Build завжди — деплой потребує актуального кешу
      - run: pnpm turbo build

--filter=...[HEAD^1] — «все, що змінилося з попереднього коміту, плюс всі залежні від цього пакети». Якщо змінили packages/ui — пересобираються і apps/web, і apps/admin.

Типові проблеми

Залежність на runtime конфіг — якщо пакет читає .env при збиранні, Turbo закешує з конкретним значенням змінної. Явно вказуйте env у pipeline:

"build": {
  "env": ["NEXT_PUBLIC_API_URL", "DATABASE_URL"]
}

Циклічні залежності — Turbo упадеe з помилкою. Рефакторинг: виділити спільну залежність у третій пакет.

Dev-режим та кешdev повинен мати "cache": false та "persistent": true. Іначе Turbo не буде запускати watchers паралельно.

Сроки

Налаштування Turborepo з нуля для проекту з 5–8 пакетами — два-три дні: створення структури, конфігурація pipeline, спільні tsconfig/eslint, налаштування remote cache, адаптація CI/CD. Перенесення існуючого проекту в monorepo додає тиждень на реструктуризацію імпортів та розв'язання залежностей.