Skip to content

ADR-001: MDX Content System Architecture

Status

Superseded by ADR-004 | Proposed | Accepted | Implemented

Version History

  • v1: 2025-03-15 - Initial acceptance and partial implementation

Context

We need a flexible content system that can:

  1. Handle MDX content from various sources (static, remote, memory)
  2. Process MDX content with modern features (MDX v3)
  3. Provide a clean developer API for rendering content
  4. Enable real-time content updates and watching
  5. Support proper error handling and debugging

The existing content system was limited to local static content, with no support for:

  • Remote content fetching
  • Content watching and real-time updates
  • Advanced error handling
  • Dynamic content injection

Decision

Implement a multi-layered MDX content system following these architectural principles:

  1. Clean Separation of Concerns:

    • Component layer: Displays MDX content, no implementation details
    • Hook layer: Coordinates content requests and component creation
    • Registry layer: Determines content source and handles caching
    • Processor layer: Handles compilation and frontmatter extraction
    • Adapter layer: Fetches raw content from different sources
  2. Data Flow:

    • Data flows from inner modules upward
    • Inner modules make decisions about their domain
    • Each module returns fully-processed data to its caller
  3. Design Patterns:

    • Adapter Pattern for content sources (memory, HTTP, etc.)
    • Registry Pattern for content discovery
    • Strategy Pattern for content loading
    • Factory Pattern for component creation

Alternatives Considered

  1. Monolithic Content Manager:

    • Pros: Simpler API, single source of truth
    • Cons: Less flexible, harder to extend, testing difficulties
    • Outcome: Rejected due to reduced flexibility and maintainability
  2. External CMS Integration:

    • Pros: More features out of the box, established ecosystem
    • Cons: External dependency, less control, additional complexity
    • Outcome: Rejected due to desire for tight integration with React ecosystem
  3. GraphQL Content API:

    • Pros: Strongly typed, efficient for multiple content types
    • Cons: Additional complexity, overkill for current needs
    • Outcome: Potential future extension but not needed for initial implementation

Consequences

Benefits

  • Flexible architecture that can adapt to different content sources
  • Clear separation of concerns for easier testing and maintenance
  • Reusable components that follow established patterns
  • Support for real-time content updates through watching
  • Enhanced debugging capabilities in development

Challenges

  • More complex architecture with more moving parts
  • Potential performance overhead with multiple layers
  • Need for comprehensive documentation
  • Requires consistent type system across layers

Implementation

The implementation follows a modular approach:

  1. Core Modules First:

    • Basic modules (adapters, compiler) are implemented first
    • Each module is functional and testable in isolation
  2. API Design:

    • Public APIs and interfaces are designed to be intuitive
    • Consistent parameter naming and error handling patterns
  3. System Integration:

    • All modules work together with consistent patterns
    • Registry coordinates different modules as a facade

Key Components:

  1. ContentAdapter - Interface for different content sources:

    • getContent(id: string): Promise<RawContent>
    • watchContent?(id: string, callback: ContentUpdate): Unsubscribe
    • readonly supportsRealtime: boolean
  2. ContentRegistry - Content discovery and access:

    • isContentAvailable(path: string): Promise<boolean>
    • getContent(path: string, options?): Promise<MdxData>
    • watchContent(path, callback): Unsubscribe
    • getContentPaths?(type?): Promise<string[]>
    • getCapabilities?(): RegistryCapabilities
  3. MDX Processor - Compile and process MDX content:

    • compileMdx(source, metadata): Promise<MdxData>
    • createMdxComponent(code, options): MdxComponent
  4. React Hooks - Interface for React components:

    • useMdxContent(path, options): ContentLoadResult
    • useContentAvailability(path, options): { isAvailable, isLoading, error }
  5. React Components - End-user interface:

    • <MdxContent contentPath="..." />

References

Released under the MIT License.