Монорепозиторий с TypeScript: организация кода для начинающих
Разработка современных приложений на TypeScript часто требует управления несколькими взаимосвязанными пакетами (например, библиотекой компонентов, бэкенд-сервисом и утилитами). Вместо того чтобы хранить каждый пакет в отдельном репозитории (мультирепозиторий), многие команды выбирают монорепозиторий — единый репозиторий, содержащий все проекты. В этой статье мы разберем, как организовать монорепозиторий с TypeScript, даже если вы новичок.
Что такое монорепозиторий и зачем он нужен?
Монорепозиторий (monorepo) — это подход, при котором код нескольких проектов (пакетов, модулей) хранится в одном репозитории. Это не означает, что все проекты сливаются в одну кучу: они остаются логически разделенными, но находятся под одной крышей.
Преимущества для проектов на TypeScript:
- Единая версия зависимостей. Вы избегаете ситуации, когда в разных пакетах используются разные версии TypeScript или одной и той же библиотеки.
- Простой рефакторинг. Изменение общего интерфейса или типа в одном месте сразу обновляется во всех зависимых пакетах.
- Упрощенная публикация. Инструменты для монорепозитория (например, Lerna или Nx) помогают автоматически публиковать только измененные пакеты.
- Общие настройки. Вы можете иметь один
tsconfig.jsonдля всех пакетов, переопределяя его при необходимости.
Инструменты для создания монорепозитория
Для работы с монорепозиторием в TypeScript существует несколько популярных инструментов:
- npm Workspaces — встроенная возможность npm, начиная с версии 7. Простая и эффективная.
- Yarn Workspaces — аналогичная функция в пакетном менеджере Yarn.
- Lerna — классический инструмент, который часто используется поверх npm или Yarn Workspaces.
- Nx — мощная система для монорепозиториев с расширенными возможностями кэширования и генерации кода.
- Turborepo — современный инструмент от Vercel, ориентированный на скорость и простоту.
В этом руководстве мы будем использовать npm Workspaces, так как это самый простой способ, не требующий установки дополнительных глобальных инструментов.
Пошаговая настройка монорепозитория с TypeScript
1. Создание корневой структуры
Начните с создания корневой папки вашего монорепозитория и инициализации package.json:
mkdir my-monorepo
cd my-monorepo
npm init -y
Теперь отредактируйте корневой package.json, добавив поле workspaces. Это укажет npm, где искать ваши пакеты:
{
"name": "my-monorepo",
"private": true,
"workspaces": [
"packages/*"
]
}
Флаг "private": true предотвращает случайную публикацию корневого пакета в npm.
2. Создание пакетов
Создайте структуру папок для ваших пакетов. Типичная структура выглядит так:
my-monorepo/
├── packages/
│ ├── utils/ # Общие утилиты
│ ├── ui/ # Библиотека компонентов
│ └── backend/ # Серверное приложение
├── package.json
└── tsconfig.json
Создайте папку packages и внутри нее — папки для каждого пакета. В каждом пакете должен быть свой package.json. Например, для пакета utils:
mkdir -p packages/utils
cd packages/utils
npm init -y
Отредактируйте packages/utils/package.json, добавив имя и, возможно, версию:
{
"name": "@my-project/utils",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc"
}
}
3. Настройка TypeScript
В корне проекта создайте базовый tsconfig.json:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["ES2020"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"outDir": "./dist",
"rootDir": "./packages"
},
"include": ["packages/**/*"],
"exclude": ["node_modules", "dist"]
}
Теперь в каждом пакете вы можете создать свой tsconfig.json, который расширяет корневой. Например, для packages/utils/tsconfig.json:
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"]
}
4. Написание кода и создание зависимостей
Создайте простой модуль в packages/utils/src/index.ts:
export function greet(name: string): string {
return `Hello, ${name}!`;
}
export function add(a: number, b: number): number {
return a + b;
}
Теперь создайте пакет backend, который будет использовать @my-project/utils. В packages/backend/package.json добавьте зависимость:
{
"name": "@my-project/backend",
"version": "1.0.0",
"scripts": {
"start": "ts-node src/index.ts"
},
"dependencies": {
"@my-project/utils": "*"
}
}
Обратите внимание на "*" — это означает, что будет использоваться любая версия пакета из вашего монорепозитория. После редактирования package.json выполните в корне проекта:
Блоги
Рекомендаций по книгам
Читайте также
Паттерны проектирования в Java: продвинутые примеры и реализация
Работа с базами данных в C#: PostgreSQL и MongoDB для начинающих
TypeScript input onChange: как правильно ловить event.target.value в 2025
Странные скобки перед именем функции в Go: разбор полетов
Какой язык проще: Python или JavaScript?