Skip to content

Migrate to monorepo structure #1420

@jasonkuhrt

Description

@jasonkuhrt

Migrate to Monorepo Structure

Overview

Transform Graffle from a single package into a monorepo with 17 focused packages. This will:

  • ✅ Enable independent versioning and releases
  • ✅ Separate generic GraphQL utilities (@graffle/grafaid) from Graffle-specific code
  • ✅ Allow extensions to be used independently
  • ✅ Improve tree-shaking and bundle sizes
  • ✅ Enable better code organization and maintainability
  • ✅ Claim the @graffle npm scope

Package Structure (17 packages)

Core Packages (5)

1. @graffle/core

Graffle-specific shared infrastructure

Contains:

  • Context system (src/context/)
  • Extension base class (Extension)
  • GlobalRegistry
  • TypeFunction
  • ContextFragments
  • RequestResult types
  • Docpar (document parser)
  • SchemaDrivenDataMap
  • Shared Graffle data structures

Used by: client, generator, all extensions


2. @graffle/grafaid

Generic GraphQL utilities (not Graffle-specific)

Contains:

  • Schema types & definitions (from src/types/Schema/)
  • GraphQL document utilities
  • Schema introspection & analysis
  • HTTP helpers
  • Execution helpers
  • Tree-shakeable, reusable GraphQL tools

Design Goal: Grafaid should be usable standalone for any GraphQL tooling, not just Graffle.

Used by: client, generator


3. @graffle/client

GraphQL Client

Contains:

  • Client implementation (src/client/)
  • Request pipeline (src/requestPipeline/)
  • Static helpers (src/static/gql)
  • Client methods
  • Export path: graffle/utilities-for-generated (re-exports from core + client for generated code)

Depends on: @graffle/core, @graffle/grafaid


4. @graffle/generator

Code Generator & CLI

Contains:

  • Generator (src/generator/)
  • CLI (src/cli/)
  • Code generation logic

Depends on: @graffle/grafaid, @graffle/core


5. graffle

Main Convenience Package

The "batteries included" package.

  • Re-exports @graffle/client and common extensions
  • Default entry point for users: npm i graffle

Extension Packages (8)

Each extension is independently publishable and versioned:

  • @graffle/extension-document-builder
  • @graffle/extension-introspection
  • @graffle/extension-throws
  • @graffle/extension-opentelemetry
  • @graffle/extension-schema-errors
  • @graffle/extension-transport-http
  • @graffle/extension-transport-memory
  • @graffle/extension-upload

All depend on: @graffle/core


Preset Packages (3)

Pre-configured extension bundles:

  • @graffle/preset-bare
  • @graffle/preset-basic
  • @graffle/preset-minimal

Dependency Graph

@wollybeard/kit (external)
          ↓
    @graffle/core
          ↓
    ┌─────┴─────────────┐
    ↓                   ↓
@graffle/grafaid   Extensions (8)
    ↓                   ↓
@graffle/client    Presets (3)
@graffle/generator      ↓
    ↓                   ↓
  graffle (meta package)

Key Design Decisions

1. Grafaid = Generic, Core = Graffle-specific

  • @graffle/grafaid: Generic GraphQL utilities, tree-shakeable, usable standalone
  • @graffle/core: Graffle-specific infrastructure (extensions, context, etc.)

2. Replace Internal Kit with @wollybeard/kit

  • Remove src/lib/anyware, src/lib/tex, src/lib/config-manager
  • Use @wollybeard/kit for these utilities

3. Keep utilities-for-generated as Export Path

  • Not a separate package
  • Export path in @graffle/client: graffle/utilities-for-generated
  • Generated code imports: import * as $$Utilities from "graffle/utilities-for-generated"

4. Independent Versioning

  • Each package can be released independently
  • Use Changesets for version management

5. Schema Types in Grafaid

  • Move src/types/Schema/ into @graffle/grafaid
  • Rely on tree-shaking to keep client bundle small

Tooling Stack

Build & Task Running

  • pnpm workspaces - Package management
  • Turborepo - Build orchestration & caching (temporary)
  • TypeScript project references - Fast, incremental builds
  • Vite/Rolldown - Bundling

Future Migration

  • Migrate to Vite+ when available (early 2026)
  • Vite+ includes built-in monorepo task runner with intelligent caching

Versioning & Publishing

  • Changesets - Independent versioning & changelog generation
  • Each package publishes to @graffle/* scope (except main graffle package)

Directory Structure

graffle/                           # Monorepo root
├── packages/
│   ├── core/                      # @graffle/core
│   ├── grafaid/                   # @graffle/grafaid
│   ├── client/                    # @graffle/client
│   ├── generator/                 # @graffle/generator
│   ├── graffle/                   # graffle (meta package)
│   │
│   ├── extensions/
│   │   ├── document-builder/      # @graffle/extension-document-builder
│   │   ├── introspection/         # @graffle/extension-introspection
│   │   ├── throws/                # @graffle/extension-throws
│   │   ├── opentelemetry/         # @graffle/extension-opentelemetry
│   │   ├── schema-errors/         # @graffle/extension-schema-errors
│   │   ├── transport-http/        # @graffle/extension-transport-http
│   │   ├── transport-memory/      # @graffle/extension-transport-memory
│   │   └── upload/                # @graffle/extension-upload
│   │
│   └── presets/
│       ├── bare/                  # @graffle/preset-bare
│       ├── basic/                 # @graffle/preset-basic
│       └── minimal/               # @graffle/preset-minimal
│
├── examples/                      # Example projects (workspace, not published)
├── website/                       # Documentation site (workspace, not published)
├── tests/                         # Integration/e2e tests
├── scripts/                       # Build/dev scripts
├── turbo.json                     # Turborepo config
├── pnpm-workspace.yaml            # pnpm workspace config
└── package.json                   # Root package.json

Migration Strategy

Phase 1: Setup Infrastructure

  • Create monorepo structure
  • Configure pnpm workspaces
  • Set up Turborepo
  • Configure TypeScript project references
  • Set up Changesets

Phase 2: Split Core Packages

  • Extract @graffle/core
  • Extract @graffle/grafaid (includes Schema types)
  • Split @graffle/client
  • Split @graffle/generator
  • Update internal imports

Phase 3: Extract Extensions

  • Move each extension to packages/extensions/*
  • Update extension imports and dependencies
  • Test extensions independently

Phase 4: Extract Presets

  • Move presets to packages/presets/*
  • Update preset dependencies

Phase 5: Create Meta Package

  • Create packages/graffle/ as main entry point
  • Re-export client + common extensions
  • Update documentation

Phase 6: Replace Kit Dependencies

  • Replace src/lib/anyware@wollybeard/kit
  • Replace src/lib/tex@wollybeard/kit
  • Replace src/lib/config-manager@wollybeard/kit
  • Remove internal lib utilities

Phase 7: Testing & Publishing

  • Run full test suite across all packages
  • Update CI/CD for monorepo
  • Publish initial versions
  • Update documentation and migration guides

References

Open Questions

  • Should examples/ and website/ be in monorepo or separate repos? Decision: Keep in monorepo
  • Versioning strategy for extensions - lock-step or independent? Decision: Independent
  • Breaking change migration path for users

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions