Настройка Monorepo (Nx) для веб-проекта

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

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Настройка Monorepo (Nx) для веб-проекта
Сложная
~3-5 рабочих дней
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1214
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    852
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    823
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    815

Настройка Monorepo (Nx) для веб-проекта

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

Nx vs Turborepo: принципиальная разница

Turborepo — task runner с кешем. Он не знает про содержимое ваших пакетов.

Nx — понимает структуру: знает, что это Next.js приложение, что то — NestJS, может генерировать компоненты, модули, тесты по шаблонам. Плагин @nx/next настраивает правила кеширования, generatory, задачи — всё автоматически.

Турбо подходит, когда уже есть сложившийся стек и нужно только ускорить CI. Nx подходит, когда команда большая и нужно стандартизировать разработку.

Инициализация

# Новый workspace
npx create-nx-workspace@latest acme --preset=apps
cd acme

# Добавляем приложения
npx nx generate @nx/next:app web --directory=apps/web
npx nx generate @nx/react:app admin --directory=apps/admin --bundler=vite
npx nx generate @nx/node:app api --directory=apps/api --framework=express

# Добавляем библиотеки
npx nx generate @nx/react:lib ui --directory=packages/ui --component
npx nx generate @nx/js:lib utils --directory=packages/utils
npx nx generate @nx/js:lib types --directory=packages/types --bundler=none

Структура и nx.json

// nx.json
{
  "$schema": "./node_modules/nx/schemas/nx-schema.json",
  "targetDefaults": {
    "build": {
      "cache": true,
      "dependsOn": ["^build"],
      "inputs": ["production", "^production"]
    },
    "lint": {
      "cache": true,
      "inputs": [
        "default",
        "{workspaceRoot}/.eslintrc.json",
        "{workspaceRoot}/.eslintignore"
      ]
    },
    "test": {
      "cache": true,
      "inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"]
    },
    "typecheck": {
      "cache": true
    }
  },
  "namedInputs": {
    "default": ["{projectRoot}/**/*", "sharedGlobals"],
    "production": [
      "default",
      "!{projectRoot}/**/*.spec.*",
      "!{projectRoot}/jest.config.*",
      "!{projectRoot}/.eslintrc.json"
    ],
    "sharedGlobals": []
  },
  "generators": {
    "@nx/react": {
      "component": {
        "style": "none",
        "classComponent": false
      }
    }
  },
  "defaultBase": "main"
}

project.json для каждого проекта

Nx использует project.json вместо scripts в package.json (хотя оба варианта поддерживаются):

// apps/web/project.json
{
  "name": "web",
  "$schema": "../../node_modules/nx/schemas/project-schema.json",
  "sourceRoot": "apps/web/src",
  "projectType": "application",
  "targets": {
    "build": {
      "executor": "@nx/next:build",
      "outputs": ["{options.outputPath}"],
      "defaultConfiguration": "production",
      "options": {
        "outputPath": "dist/apps/web"
      },
      "configurations": {
        "development": {
          "outputPath": "apps/web"
        },
        "production": {
          "outputPath": "dist/apps/web"
        }
      }
    },
    "serve": {
      "executor": "@nx/next:server",
      "defaultConfiguration": "development",
      "options": {
        "buildTarget": "web:build",
        "dev": true
      }
    },
    "lint": {
      "executor": "@nx/eslint:lint",
      "outputs": ["{options.outputFile}"],
      "options": {
        "lintFilePatterns": ["apps/web/**/*.{ts,tsx}"]
      }
    },
    "test": {
      "executor": "@nx/jest:jest",
      "outputs": ["{workspaceRoot}/coverage/apps/web"],
      "options": {
        "jestConfig": "apps/web/jest.config.ts"
      }
    },
    "typecheck": {
      "executor": "nx:run-commands",
      "options": {
        "command": "tsc --noEmit",
        "cwd": "apps/web"
      }
    }
  },
  "tags": ["type:app", "scope:web"]
}

Tags и lint правила для архитектурных ограничений

Одна из сильных сторон Nx — enforcement границ между модулями:

// .eslintrc.json (корневой)
{
  "plugins": ["@nx"],
  "rules": {
    "@nx/enforce-module-boundaries": [
      "error",
      {
        "enforceBuildableLibDependency": true,
        "depConstraints": [
          {
            "sourceTag": "type:app",
            "onlyDependOnLibsWithTags": ["type:lib", "type:util"]
          },
          {
            "sourceTag": "scope:web",
            "onlyDependOnLibsWithTags": ["scope:web", "scope:shared"]
          },
          {
            "sourceTag": "scope:api",
            "onlyDependOnLibsWithTags": ["scope:api", "scope:shared"]
          },
          {
            "sourceTag": "type:util",
            "onlyDependOnLibsWithTags": ["type:util"]
          }
        ]
      }
    ]
  }
}

Это значит: apps/web не может импортировать из apps/api, scope:web не может импортировать scope:api-библиотеки. Нарушение — ошибка линтера прямо в IDE.

Граф зависимостей

# Визуализация в браузере
npx nx graph

# Только для конкретного проекта
npx nx graph --focus=web

# Что затронуто изменениями в ветке
npx nx affected:graph

Граф помогает понять цену изменения: если меняешь packages/ui, сразу видишь какие приложения нужно пересобрать.

Запуск только affected проектов

# Тесты только для затронутых проектов
npx nx affected:test

# Сборка только изменившегося
npx nx affected:build

# С базой сравнения
npx nx affected:test --base=origin/main --head=HEAD

# Параллельно, не более 4 задач
npx nx affected:build --parallel=4

Генераторы: стандартизация разработки

Nx позволяет писать собственные генераторы — скрипты, которые создают файлы по шаблонам:

// tools/generators/feature/index.ts
import type { Tree } from '@nx/devkit';
import {
  formatFiles,
  generateFiles,
  names,
  offsetFromRoot,
} from '@nx/devkit';
import * as path from 'path';

interface FeatureGeneratorSchema {
  name: string;
  project: string;
}

export default async function featureGenerator(
  tree: Tree,
  options: FeatureGeneratorSchema
) {
  const projectRoot = `apps/${options.project}/src/features`;
  const { fileName, className } = names(options.name);

  generateFiles(
    tree,
    path.join(__dirname, 'files'),  // шаблоны
    `${projectRoot}/${fileName}`,
    {
      className,
      fileName,
      offsetFromRoot: offsetFromRoot(projectRoot),
    }
  );

  await formatFiles(tree);
}
# Запуск генератора
npx nx generate @acme/tools:feature --name=user-profile --project=web

Генератор создаёт все нужные файлы: компонент, тест, сторсfile, index.ts для реэкспорта — по заранее утверждённому шаблону.

Nx Cloud: distributed task execution

Nx Cloud позволяет распределить выполнение задач между несколькими агентами CI:

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

jobs:
  agents:
    name: Nx Cloud Agent ${{ matrix.agent }}
    runs-on: ubuntu-latest
    strategy:
      matrix:
        agent: [1, 2, 3]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20 }
      - run: npm ci
      - run: npx nx-cloud start-agent
        env:
          NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}

  main:
    runs-on: ubuntu-latest
    needs: []
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }
      - uses: actions/setup-node@v4
        with: { node-version: 20 }
      - run: npm ci
      - run: npx nx-cloud start-ci-run --distribute-on="3 linux-medium-js"
      - run: npx nx affected -t lint typecheck test build
      - run: npx nx-cloud stop-all-agents
        if: always()
        env:
          NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}

При 20+ проектах DTE сокращает CI с 30 минут до 7–10.

Миграция с Turborepo

Если уже используете Turbo:

# Nx умеет импортировать существующий workspace
npx nx@latest init
# Следуем инструкциям — Nx определит структуру и добавит свои конфиги

Сроки

Настройка Nx с нуля для 6–10 проектов — три-пять дней: создание workspace, настройка плагинов, module boundaries, генераторов, CI/CD. Миграция существующего monorepo — неделя-полторы в зависимости от числа кастомных конфигов сборки.