npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mf-mono-project-graph

v1.0.4

Published

CLI and graph builder for React/TS monorepos: dependency graph, FSD support, symbol-level analysis, Cursor AI integration.

Readme

mf-mono-project-graph / react-graph

npm license node

CLI и программная библиотека для построения графа зависимостей React/TypeScript‑монорепо с FSD-архитектурой и tsconfig aliases. Строит единый граф по репозиторию, сохраняет его в .graph/project-graph.json и даёт быстрые структурные ответы через CLI без повторного чтения кода.


Кратко: чем полезен граф

Граф выступает картой фронтенд‑монорепо: помогает сузить десятки файлов «наугад» до нескольких релевантных и экономит токены/время агента.

Оценки пользы из реального опыта работы агента с фронтенд‑монорепо:

| Задача | Оценка | |--------|--------| | Impact-анализ: что затронет изменение X | 9/10 | | Состав страницы/виджета: из каких файлов состоит экран | 9/10 | | Навигация по роутингу: какие страницы есть, какие entry-файлы | 8/10 | | Зависимости фичи от entities/widgets | 8/10 | | Изменение API модуля: кто импортирует и кому обновить контракт | 8/10 | | FSD-рефакторинг: перенос слоя, проверка cross-слайс границ | 8/10 | | Оценка объёма правок перед задачей | 7/10 | | Поиск мёртвого кода и неиспользуемых модулей | 7/10 | | Онбординг: как устроен сервис X | 7/10 | | Связи компонент–хук на symbol-уровне | 6/10 |

Общая полезность для агента в фронтенд-монорепо: 8/10.

Граф сильнее всего помогает в структурных задачах (зависимости, impact, границы приложений, рефакторинг, оценка объёма). Для тонкостей логики и дебага по‑прежнему нужно читать код, но граф существенно сужает область поиска.


Установка

npm install mf-mono-project-graph

TypeScript >=5.0.0 — optional peer dependency.
Пакет объявляет

"peerDependencies": {
  "typescript": ">=5.0.0"
},
"peerDependenciesMeta": {
  "typescript": {
    "optional": true
  }
}

и использует TS Compiler API из зависимостей проекта. npm не тянет свою копию TypeScript и не требует его наличия принудительно, но без TypeScript >=5.0.0 в проекте сборка графа работать не будет.
Конфигурация peerDependencies + peerDependenciesMeta.optional помогает мягче интегрировать пакет в существующее дерево зависимостей монорепо, но не гарантирует отсутствие предупреждений npm warn ERESOLVE overriding peer dependency.

Монорепо (npm workspaces)

В монорепо с несколькими воркспейсами рекомендуется устанавливать пакет в корне:

npm install mf-mono-project-graph --save-dev

При установке в реальном монорепо предупреждения ERESOLVE overriding peer dependency могут появляться и зависят от конфигурации всего проекта (версий TypeScript и других пакетов с peerDependencies).
Если при установке ты видишь такие предупреждения, имеет смысл проверить через npm ls typescript и npm ls --all пакеты с конфликтующими peerDependencies по TypeScript и связанным библиотекам — источник конфликта может быть как в mf-mono-project-graph, так и в других зависимостях.


Быстрый старт

1. Инициализировать Cursor-файлы

npx react-graph init-cursor --root .

Копирует три шаблона в .cursor/rules/, .cursor/skills/ и .cursor/agents/ — настраивает главного агента Cursor на работу с графом в двух режимах: через субагента graph-agent или напрямую через skill.

2. Собрать граф

npx react-graph build --root . --json

Граф сохраняется в одном местекорень/.graph/project-graph.json. Для монорепо всегда указывай --root на корень репозитория (не на каталог приложения/микрофронта). Пересобирай после изменений в services/** или package.json.

3. Задать вопрос к графу

Например, посмотреть, кто зависит от файла/символа:

npx react-graph who-uses "<nodeId>" --root . --json

CLI

Общие флаги

| Флаг | Алиас | Команды | Описание | |------|-------|---------|----------| | --root <path> | -r | все | Корень проекта (по умолчанию: cwd). В монорепо — только корень репо: граф один (.graph/ в корне), без дублей в микрофронтах. | | --json | — | все | JSON-вывод вместо текстового | | --resolve-packages | -R | deps, node-info | Развернуть внутренние package:* в конкретные файлы | | --files-only | -f | deps, node-info | Вернуть только файловые узлы, без package:* | | --partial | -p | find | Поиск по подстроке вместо точного совпадения имени символа | | --slice <slice> | — | find | Фильтр по FSD-слайсу (например, entityDrawer, projectData) |

build

npx react-graph build --root <path> [--json]

Строит/обновляет граф. JSON-вывод: { rootDir, nodes, edges, durationMs, graphSizeBytes }.

deps

npx react-graph deps "<nodeId>" --root <path> [--json] [-R] [-f]

Прямые и транзитивные зависимости узла.

{
  "node": "<nodeId>",
  "directDependencies": ["..."],
  "transitiveDependencies": ["..."]
}

who-uses

npx react-graph who-uses "<nodeId>" --root <path> [--json]

Обратные зависимости — кто зависит от указанного узла. Используется для impact-анализа.

{ "node": "<nodeId>", "users": ["..."] }

node-info

npx react-graph node-info "<nodeId>" --root <path> [--json] [-R] [-f]

Всё в одном: тип узла, прямые/транзитивные зависимости, пользователи, пакеты.

find

npx react-graph find "<name>" --root <path> [--json] [--layer <fsd-layer>] [--mf <mf-name>] [--kind <component|hook|function>] [--partial|-p] [--slice <slice-name>]

Ищет symbol-узлы в графе по имени символа (компонент/хук/функция) без знания пути к файлу. Возвращает nodeId, который можно передавать в deps, who-uses, node-info.

| Флаг | Описание | |------|----------| | --layer <layer> | Фильтр по FSD-слою: pages, widgets, features, entities, shared, app | | --mf <name> | Фильтр по имени микрофронта (подстрока): gantt-v2-app, host-app | | --kind <kind> | Фильтр по типу символа: component, hook, function | | --partial, -p | Поиск по подстроке вместо точного совпадения: find "Gantt" --partial найдёт GanttComponent, GanttHeader и т.п. | | --slice <slice> | Фильтр по FSD-слайсу: entityDrawer, projectData — для сужения внутри слоя |

JSON-вывод (точный поиск):

{
  "query": "ProjectData",
  "filters": { "layer": "pages", "mf": "gantt-v2-app" },
  "count": 1,
  "matches": [
    {
      "nodeId": "symbol:/abs/.../ProgectData/index.tsx#ProjectData",
      "type": "symbol",
      "symbolKind": "component",
      "layer": "pages",
      "slice": "projectData",
      "mf": "gantt-v2-app",
      "filePath": "/abs/.../ProgectData/index.tsx"
    }
  ]
}

При count: 0 в ответе только query, filters, count, matches (пустой массив). Используй --partial для поиска по подстроке или уточни фильтры.

Примеры использования:

# Точный поиск (по умолчанию) — MainLayout есть во всех МФ, уточняем через --mf
npx react-graph find "MainLayout" --root . --json --mf reports-app

# Частичный поиск — найти всё связанное с "Gantt"
npx react-graph find "Gantt" --root . --json --partial --mf gantt-v2-app

# Поиск хуков в конкретном слайсе
npx react-graph find "use" --root . --json --partial --layer entities --slice entityDrawer

# Получаем nodeId и дальше работаем через deps/who-uses
npx react-graph deps "symbol:/abs/.../MainLayout.tsx#MainLayout" --root . --json --files-only

init-cursor

npx react-graph init-cursor [--root <path>]

Копирует три шаблона в целевой проект (создаёт каталоги при необходимости):

| Файл | Назначение | |------|------------| | .cursor/rules/react-graph.mdc | Правило для главного агента: когда и как использовать граф, два режима работы, CLI API | | .cursor/skills/react-graph.mdc | Skill для прямой работы агента с графом (по явному запросу пользователя) | | .cursor/agents/graph-agent.md | Суб-агент graph-agent: flow из шагов, правило «только CLI», прозрачный summary ответа |


Модель графа

Простая ASCII-схема для интуиции:

        project
           |
       package:app/*
        /       \
   file (page)  file (widget)
        \       /
      symbol (component)

Типы узлов

| Тип | ID | Ключевые meta-поля | |-----|----|--------------------| | project | project:<absPathToRoot> | rootDir | | file | <absPath/to/file.tsx> | filePath, layer, slice | | package | package:<name> | — | | symbol | symbol:<absPath>#<ExportName> | symbolName, symbolKind, exportKind, loc, layer, slice |

FSD-слои (meta.layer): app / pages / widgets / features / entities / shared / unknown.

package:* бывают:

  • Внешние npm: package:react, package:@reduxjs/toolkit
  • Внутренние alias-пакеты (FSD-слои): package:widgets/*, package:entities/*, package:features/*, package:pages/*, package:app/*, package:shared/*
  • Приложения (из router config): package:app/<appName> с meta.kind: "app"
  • Страницы (из router config): package:pages/<slice> с meta.kind: "page", routeId, routePath

Типы рёбер

| Тип | Направление | Смысл | |-----|-------------|-------| | imports | file → file/package | Файл импортирует другой файл или пакет | | depends_on | project → package, package:* → file | Зависимость из package.json; резолв alias-пакета в файлы | | belongs_to_pkg | package:* → file | Файл входит в состав alias-пакета | | contains | file → symbol | Файл содержит символ | | exports_symbol | file → symbol | Файл экспортирует символ | | calls | symbol → symbol | Символ вызывает другой символ | | uses_jsx | symbol → symbol | Символ использует другой символ как JSX-компонент |

Форматы nodeId

# Файл
/abs/path/src/features/auth/ui/LoginForm.tsx

# npm-пакет
package:react
package:@reduxjs/toolkit

# Внутренний alias-пакет (FSD)
package:widgets/digest
package:entities/user
package:app/host-app

# Символ
symbol:/abs/path/src/widgets/Header/ui/Header.tsx#Header
symbol:/abs/path/src/app/router/AppRouter.tsx#default

Паттерн работы с агентом

Правило: сначала граф, потом точечное чтение кода.

# 1. Пересобрать граф (если менялись файлы)
npx react-graph build --root . --json

# 2. Получить структуру
npx react-graph node-info "<nodeId>" --root . --json --resolve-packages --files-only

# 3. Прямые зависимости (для понимания скоупа правок)
npx react-graph deps "<nodeId>" --root . --json --resolve-packages --files-only

# 4. Обратные зависимости (impact-анализ)
npx react-graph who-uses "<nodeId>" --root . --json

По JSON-ответу агент выбирает минимальный набор файлов и читает только их.


Cursor-интеграция

После npx react-graph init-cursor --root . в проекте появляются три файла:

| Файл | Назначение | |------|------------| | .cursor/rules/react-graph.mdc | Правило для главного агента (alwaysApply): когда граф обязателен, два режима работы, CLI API с контрактами | | .cursor/skills/react-graph.mdc | Skill: прямая работа агента с графом по явному запросу пользователя | | .cursor/agents/graph-agent.md | Суб-агент graph-agent: flow, правило «только CLI», прозрачный summary CLI-вывода |

Поддерживаются два режима: субагент (главный агент спрашивает разрешение пользователя, делегирует graph-agent) и skill (агент работает с графом напрямую по явной просьбе). Граф пересобирается каждый раз перед началом работы.


Интеграция через npm-скрипты

Добавь в package.json проекта для удобного вызова из корня:

"scripts": {
  "graph:build":     "react-graph build --root . --json",
  "graph:deps":      "react-graph deps --root .",
  "graph:who-uses":  "react-graph who-uses --root .",
  "graph:node-info": "react-graph node-info --root .",
  "graph:find":      "react-graph find --root ."
}

Примеры:

npm run graph:node-info -- "/abs/path/DigestPage.tsx" --json --resolve-packages --files-only
npm run graph:find -- "MainLayout" --json --mf reports-app

Программный API

import { buildGraph, loadGraph, QueryEngine, type ProjectGraph } from "mf-mono-project-graph";

const graph = buildGraph({ rootDir: "/abs/path/to/frontend" });
const engine = new QueryEngine(graph);
engine.deps(nodeId, { transitive: true, resolvePackages: true });
engine.whoUses(nodeId);

Ограничения

  • Barrel-файлы и entry-точки (entities/*/index.ts, pages/*/index.tsx) могут иметь мало входящих imports-рёбер, потому что на них ссылаются через alias-пакеты, а не напрямую. Для поиска мёртвого кода дополнительно смотри belongs_to_pkg.
  • Symbol-уровень неполный: рёбра calls/uses_jsx строятся только для верхнеуровневых функций/хуков/компонентов; namespace-импорты, динамические вызовы и обращения к методам объектов могут не давать рёбер.
  • Module Federation remotes (import("digest/DigestApp")) отражаются как package:digest/DigestApp — внутренняя структура remote-модулей не сканируется.
  • Конфиги и декларации (webpack.config.js, *.d.ts) почти не имеют входящих рёбер: пустой who-uses не означает мёртвый код.
  • Router config детектируется только по паттерну **/app/router/config.*; нестандартные пути не покрываются.
  • Установка и peer-зависимости TypeScript — пакет использует peerDependencies + peerDependenciesMeta.optional для typescript >=5.0.0, чтобы не тянуть свою копию TS и лучше вписываться в монорепо. Тем не менее, при установке в проектах с конфликтующими peerDependencies по TypeScript и другим библиотекам возможны предупреждения npm warn ERESOLVE overriding peer dependency; это известное ограничение, а не гарантированно устранённая проблема.
  • Сам граф весит ~10 MB JSON — целиком в контекст агента не тянется; работа идёт через CLI и уже отфильтрованный вывод.

Troubleshooting

  • Permission denied при запуске CLI (npx react-graph)

    • В версиях <1.0.1 бинарь dist/bin/cli.js мог публиковаться без права на выполнение, из-за чего запуск react-graph заканчивался ошибкой Permission denied.
    • Начиная с >=1.0.1 проблема исправлена: скрипт сборки scripts/copy-bin.js выставляет chmod 755 для dist/bin/cli.js, а в >=1.0.2 добавлен хук prepack, который гарантирует запуск сборки перед публикацией.
    • Если видишь Permission denied в реальном проекте, достаточно обновить пакет до актуальной версии mf-mono-project-graph; ручной chmod в node_modules не требуется.

Links

  • Repository: https://github.com/AlekseyGogolev/graph_agent
  • npm: https://www.npmjs.com/package/mf-mono-project-graph