Skip to content

Monorepo Migration: Modular Architecture for Enhanced Development and Publishing #116

@draedful

Description

@draedful

Motivation

As @gravity-ui/graph continues to evolve, we need a more flexible architecture that enables:

  1. Independent Plugin Development: New layers and features can be developed and published without requiring a full library release
  2. Selective Consumption: Users can import only the parts they need, reducing bundle size
  3. Enhanced Tooling: Separate packages for development tools (devtools, minimap) that don't bloat the core library
  4. Better Maintenance: Clear separation of concerns makes the codebase easier to maintain and contribute to
  5. Ecosystem Growth: Third-party developers can more easily extend the library with custom layers and plugins

The current monolithic structure limits our ability to iterate quickly on supplementary features while maintaining stability in the core library.

Proposed Solution

Transform @gravity-ui/graph into a monorepo with 6 focused packages:

Package Architecture

graph LR
    subgraph "Main Package with Routing"
        MAIN["@gravity-ui/graph<br/>package.json with exports routing"]
    end
    
    subgraph "Internal Packages"
        PRIM["@gravity-ui/graph-primitives<br/>• shapes: curvePolyline, triangle, polyline<br/>• renderers: text, svg, render<br/>• basic types: TPoint, TRect, IPoint, IRect<br/>• simple utils: clamp"]
        
        CORE["@gravity-ui/graph-core<br/>• lib/: CoreComponent, Component, Scheduler<br/>• store/: RootStore, blocks, connections<br/>• services/: Layer, Camera, HitTest<br/>• components/canvas/<br/>• api/: PublicGraphApi<br/>• graph.ts: main class<br/>• utils/functions, utils/types"]
        
        REACT["@gravity-ui/graph-react<br/>• GraphCanvas<br/>• hooks: useGraph, useLayer<br/>• React components"]
        
        DEVTOOLS["@gravity-ui/graph-devtools<br/>• DevToolsLayer<br/>• ruler and crosshairs"]
        
        MINIMAP["@gravity-ui/graph-minimap<br/>• MiniMapLayer<br/>• navigation minimap"]
    end
    
    PRIM --> CORE
    PRIM --> REACT
    CORE --> REACT
    CORE --> DEVTOOLS
    CORE --> MINIMAP
    
    CORE --> MAIN
    REACT --> MAIN
    DEVTOOLS --> MAIN
    MINIMAP --> MAIN
Loading

Package Details

1. @gravity-ui/graph-primitives

Foundation package with basic building blocks

  • Geometric shapes (curvePolyline, triangle, polyline)
  • Rendering utilities (text, svg, render)
  • Core types (TPoint, TRect, IPoint, IRect)
  • Simple utilities (clamp, basic math functions)

2. @gravity-ui/graph-core

Consolidated core functionality

  • Component system (lib/)
  • State management (store/)
  • Core services (services/)
  • Canvas components (components/canvas/)
  • Public API (api/, graph.ts)
  • Remaining utilities

Rationale: These modules are tightly coupled and only valuable together

3. @gravity-ui/graph-react

React integration layer

  • GraphCanvas component
  • React hooks (useGraph, useLayer, etc.)
  • React-specific components and utilities

4. @gravity-ui/graph-devtools

Development tools plugin

  • DevTools layer with rulers and crosshairs
  • Independent package for development-time features
  • Peer dependency on @gravity-ui/graph-core

5. @gravity-ui/graph-minimap

Navigation minimap plugin

  • Minimap layer for graph navigation
  • Independent package for optional UI enhancement
  • Peer dependency on @gravity-ui/graph-core

6. @gravity-ui/graph

Main package with routing

  • Consolidates all packages with proper exports
  • Maintains backward compatibility
  • Provides clean API surface

Implementation Plan

Phase 1: Monorepo Setup

packages/
├── primitives/          # @gravity-ui/graph-primitives
├── core/               # @gravity-ui/graph-core  
├── react/              # @gravity-ui/graph-react
├── devtools/           # @gravity-ui/graph-devtools
├── minimap/            # @gravity-ui/graph-minimap
└── graph/              # @gravity-ui/graph (main with routing)

Phase 2: Package Configuration

Main package package.json with exports routing:

{
  "name": "@gravity-ui/graph",
  "exports": {
    ".": {
      "types": "./dist/core/index.d.ts",
      "default": "./dist/core/index.js"
    },
    "./react": {
      "types": "./dist/react/index.d.ts", 
      "default": "./dist/react/index.js"
    },
    "./primitives": {
      "types": "./dist/primitives/index.d.ts",
      "default": "./dist/primitives/index.js"
    },
    "./devtools": {
      "types": "./dist/devtools/index.d.ts",
      "default": "./dist/devtools/index.js"
    },
    "./minimap": {
      "types": "./dist/minimap/index.d.ts", 
      "default": "./dist/minimap/index.js"
    }
  }
}

Phase 3: Migration Strategy

  1. Create packages structure while maintaining single build output
  2. Update internal dependencies and imports
  3. Configure build system and publishing workflow
  4. Update documentation and examples

Tools and Technologies

Build System

  • TypeScript Composite Projects: Use TypeScript's composite option for incremental builds and project references
  • Rollup: For optimized bundling and tree-shaking support
  • Shared build configuration: Consistent build setup across all packages

Publishing and Versioning

  • Changesets: Industry-standard tool for managing versions and changelogs in monorepos
  • Independent versioning: Each package can evolve at its own pace
  • Coordinated releases: Core updates can trigger dependent package updates

Development Workflow

  • Workspaces: npm/yarn workspaces for dependency management
  • Shared tooling: ESLint, Prettier, TypeScript configs
  • Cross-package development: Easy local development with package linking

Benefits

For Users

  • Smaller bundles: Import only needed functionality
  • Faster adoption: Try specific features without full library commitment
  • Clear upgrade paths: Update individual packages as needed

For Maintainers

  • Independent releases: Ship devtools improvements without core library changes
  • Clear boundaries: Easier to reason about code organization
  • Better testing: Isolated testing per package
  • Community contributions: Easier for contributors to focus on specific areas

For Ecosystem

  • Plugin development: Clear pattern for extending with custom layers
  • Third-party tools: Better foundation for community-built extensions
  • Framework integration: Other frameworks can consume core without React dependencies

Backward Compatibility

The main @gravity-ui/graph package will maintain 100% backward compatibility through proper exports routing. Existing users won't need to change any import statements.

Next Steps

  1. Community feedback on this RFC
  2. Proof of concept with TypeScript composite setup
  3. Migration timeline planning
  4. Documentation updates for new architecture

This migration represents a significant step toward a more modular, maintainable, and extensible @gravity-ui/graph ecosystem while preserving the seamless developer experience users expect.

Sub-issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions