Монорепозиторий с TypeScript: организация кода на практике

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Монорепозиторий с TypeScript: организация кода на практике

Современная фронтенд- и бэкенд-разработка всё чаще сталкивается с проблемой управления несколькими взаимосвязанными проектами. Когда количество пакетов, библиотек и приложений растёт, традиционный подход с отдельными репозиториями (multi-repo) начинает тормозить разработку: дублирование кода, сложности с синхронизацией версий и долгие циклы ревью. Решение — монорепозиторий (monorepo), особенно в связке с TypeScript. В этой статье мы разберём практические аспекты организации кода в монорепозитории на TypeScript: от выбора инструментов до конкретных примеров структуры и настройки.

Что такое монорепозиторий и зачем он нужен TypeScript-проектам?

Монорепозиторий — это подход, при котором код нескольких проектов (пакетов, библиотек, сервисов) хранится в одном Git-репозитории. Для TypeScript это особенно актуально, так как язык строгой типизации позволяет легко переиспользовать общие типы и интерфейсы между разными частями системы.

Основные преимущества монорепозитория с TypeScript:

  • Единая версия зависимостей — исключается ситуация, когда в разных проектах используются разные версии одной библиотеки.
  • Переиспользование кода — общие типы, утилиты и конфигурации легко доступны всем пакетам.
  • Атомарные коммиты — изменения, затрагивающие несколько пакетов, можно коммитить вместе.
  • Упрощение CI/CD — один пайплайн для сборки и тестирования всех частей.

Однако монорепозиторий требует дисциплины в организации кода. Без правильной структуры он превращается в "свалку". TypeScript помогает навести порядок благодаря строгой типизации и модульной системе.

Выбор инструмента для управления монорепозиторием

На рынке есть несколько популярных инструментов для работы с монорепозиториями. Рассмотрим два самых распространённых для TypeScript: Nx и Turborepo.

Nx — мощная система с поддержкой монорепозиториев, генерацией кода и продвинутым кэшированием. Она отлично подходит для больших проектов с множеством пакетов.

Turborepo — более лёгкий и быстрый инструмент от Vercel, ориентированный на простоту. Он идеален для средних проектов и команд, которые хотят минимальную конфигурацию.

Пример базовой настройки с Turborepo:

// turbo.json
{
  "$schema": "https://turbo.build/schema.json",
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    },
    "test": {
      "dependsOn": ["build"]
    },
    "lint": {}
  }
}

Для TypeScript обязательна настройка tsconfig.json с поддержкой project references. Это позволяет компилятору понимать зависимости между пакетами.

// tsconfig.base.json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "composite": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "outDir": "./dist",
    "rootDir": "./src"
  }
}

Практическая организация структуры монорепозитория

Ключевой принцип — разделение кода на логические слои. Рассмотрим типовую структуру для TypeScript-монорепозитория с веб-приложением и бэкендом:

monorepo/
├── apps/
│   ├── web/          # Frontend приложение (React, Vue, etc.)
│   └── api/          # Backend сервис (Express, NestJS)
├── packages/
│   ├── shared/       # Общие типы и интерфейсы
│   ├── utils/        # Утилитарные функции
│   ├── ui/           # UI-компоненты (если используется)
│   └── config/       # Общие конфигурации (eslint, tsconfig)
├── tools/            # Скрипты и инструменты для CI/CD
├── turbo.json
├── package.json
└── tsconfig.base.json

Каждый пакет в packages/ должен иметь свой package.json и tsconfig.json, наследующий от базового. Например, для пакета shared:

// packages/shared/package.json
{
  "name": "@monorepo/shared",
  "version": "1.0.0",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "scripts": {
    "build": "tsc",
    "dev": "tsc --watch"
  },
  "dependencies": {
    "typescript": "^5.0.0"
  }
}
// packages/shared/tsconfig.json
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src"]
}

Пример общих типов в пакете shared:

// packages/shared/src/types/user.ts
export interface User {
  id: string;
  email: string;
  name: string;
  role: 'admin' | 'user';
}

export type CreateUserDto = Omit<User, 'id'>;

Теперь эти типы можно импортировать в любом приложении:

// apps/api/src/routes/user.ts
import { User, CreateUserDto } from '@monorepo/shared';

export function createUser(data: CreateUserDto): User {
  // логика создания пользователя
  return { id: generateId(), ...data };
}

Управление зависимостями и сборка

В монорепозитории TypeScript важно правильно настроить зависимости между пакетами. Используйте workspace-ссылки (workspace protocol) в package.json корневого проекта:

// package.json (корневой)
{
  "private": true,
  "workspaces": [
    "apps/*",
    "packages/*"
  ],
  "scripts": {
    "build": "turbo run build",
    "test": "turbo run test",
    "lint": "turbo run lint"
  }
}

Для локальной разработки используйте npm link или workspace-зависимости. Например, в apps/web/package.json:

{
  "                

Блоги

Рекомендаций по книгам