Libs Structure

Ecosistema completo para organización y gestión de contenido con interfaces espaciales

NX Library Architecture & Import Resolution

📅 Last Updated: October 23, 2025
📊 Current Status: 42 libraries building successfully with custom builder

Overview

This document explains our NX monorepo library architecture, how imports work, and best practices for creating and maintaining libraries.

🏗️ Our Custom Build System

We use a custom Angular library builder instead of the standard NX executors:

Why Custom Builder?

Builder: node tools/scripts/build/build-angular-library.js

🚨 Historical Context: Import Issues (RESOLVED)

The Problem We Experienced

We encountered inconsistent import resolution errors like:

Cannot find module '@ux-portal' or its corresponding type declarations.
Cannot find module '@storage-system' or its corresponding type declarations.

Root Causes (All Fixed)

  1. ❌ Mixed Executors: Libraries used different build systems (@nx/js:tsc vs @nx/angular:ng-packagr-lite)
  2. ❌ Missing Decorator Support: Standard builders didn't set TypeScript decorator flags
  3. ❌ Inconsistent Builds: Different libraries built differently
  4. ✅ Solution: Unified custom builder for all Angular libraries

📚 Current Library Architecture

We have 42 Angular libraries in our monorepo, all using the same custom builder:

Angular Libraries with Custom Builder

Purpose: All libraries - components, services, utilities, everything

Characteristics:

Examples in our codebase (42 total):

Project.json Structure:

{
  "name": "my-library-name",
  "targets": {
    "build": {
      "executor": "nx:run-commands",
      "outputs": ["{workspaceRoot}/dist/libs/my-library-name"],
      "options": {
        "command": "node tools/scripts/build/build-angular-library.js my-library-name"
      },
      "configurations": {
        "production": {
          "command": "node tools/scripts/build/build-angular-library.js my-library-name"
        }
      },
      "defaultConfiguration": "production"
    }
  }
}

tsconfig.lib.json:

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "../../dist/libs/my-library-name",
    "declaration": true,
    "declarationMap": true,
    "inlineSources": true,
    "incremental": false,  // Important: prevents .tsbuildinfo issues
    "types": ["node"]
  },
  "files": [],
  "include": ["src/**/*.ts"],
  "exclude": [
    "src/**/*.spec.ts",
    "src/**/*.test.ts",
    "jest.config.ts",
    "vite.config.ts",
    "vitest.config.ts"
  ]
}

Nested Libraries

Some libraries have a hierarchical structure (e.g., theme-system):

libs/theme-system/
├── theme-runtime/          # Runtime theme services
├── theme-dev-tools/        # Development tools
├── theme-styles/           # SCSS styles
└── theme-showcase/         # Example components

Important: Nested library names in project.json must include the parent:

{
  "name": "theme-system-theme-runtime"  // Not just "theme-runtime"
}

This ensures proper dependency resolution in our build system.

✅ How Imports Work Now

All imports work seamlessly because:

  1. Unified Builder: All libraries use the same custom builder
  2. Proper Decorators: TypeScript decorators are configured correctly
  3. Consistent Output: All libraries output to dist/libs/
  4. Path Mappings: tsconfig.base.json maps all library aliases

Import Examples

// ✅ Library-to-library imports (use aliases)
import { StorageService } from '@storage-system';
import { ThemeManagerService } from '@theme-system';
import { UxPortalService } from '@libs-ux/ux-portal';
import type { SafeAny } from '@libs-foundational/core-models';

// ✅ App-to-library imports (same aliases)
import { UxCardComponent } from '@ux-ui-core';
import { autoFlashState } from '@flash-persistence';

Build Order

Libraries must be built before apps can import them:

# Build all libraries first
yarn build:libs:auto

# Then build/serve your app
yarn nx serve my-app

Why? Apps import from dist/libs/, not libs/ source code.

🎯 Best Practices

1. Always Use the Custom Builder

Every new library should use our custom builder in project.json:

{
  "targets": {
    "build": {
      "executor": "nx:run-commands",
      "options": {
        "command": "node tools/scripts/build/build-angular-library.js my-library"
      }
    }
  }
}

2. Library Architecture

┌─────────────────────────────────────────────┐
│          42 Angular Libraries               │
│          (Custom Builder)                   │
│                                             │
│ • core-models        • ux-ui-core          │
│ • storage-system     • ux-portal           │
│ • flash-persistence  • editor-ui           │
│ • theme-system-*     • prompt-system       │
│ • gograb-ai          • widgets             │
│                                             │
└──────────────────┬──────────────────────────┘
                   │
                   ▼
┌─────────────────────────────────────────────┐
│             Applications                     │
│                                             │
│ • ux-test          • space-map             │
│ • editor-web       • docs-angular          │
│ • atlas-admin      • space-admin           │
└─────────────────────────────────────────────┘

3. Import Strategy

Always use aliases for library imports:

// ✅ Correct: Use aliases everywhere
import { StorageService } from '@storage-system';
import { UxPortalService } from '@libs-ux/ux-portal';
import type { SafeAny } from '@libs-foundational/core-models';

// ❌ Wrong: Don't use relative paths across libraries
import { StorageService } from '../../storage-system/src/lib/storage.service';

📋 Current Library Status

All 42 Libraries Building Successfully ✅

All libraries use the same custom builder and build successfully:

Library Category Count Examples
Core Systems 5 core-models, storage-system, flash-persistence
Theme System 5 theme-system, theme-system-theme-runtime, theme-system-theme-styles
UI Components 12 ux-ui-core, ux-ui-extended, ux-portal, widgets
Editor 3 editor-ui, editor-web-lib, editor-state
Features 8 gograb-ai, prompt-system, singularity-lib, cosmic-backgrounds
Utilities 9 shared-ui, ux-menu, ux-test-lib, ux-icons

Library Health

Build Command

# Build all 42 libraries in correct dependency order
yarn build:libs:auto

# Output: "✅ Libraries: 42 succeeded, 0 failed"

🏗️ Creating New Libraries

Standard Process

All libraries use the same process:

# 1. Generate Angular library
npx nx g @nx/angular:library my-library-name

# 2. Update project.json to use custom builder
# Replace the build target with:
{
  "build": {
    "executor": "nx:run-commands",
    "options": {
      "command": "node tools/scripts/build/build-angular-library.js my-library-name"
    }
  }
}

# 3. Update tsconfig.lib.json
# Set "incremental": false

# 4. Build the library
yarn nx build my-library-name

Library Naming Conventions

Type Naming Example
Simple Library kebab-case storage-system, prompt-system
Nested Library parent-child format theme-system-theme-runtime
UI Components ux- prefix ux-ui-core, ux-portal
Core Systems Descriptive names core-models, flash-persistence

For Nested Libraries

When creating libraries in subdirectories (like libs/theme-system/theme-runtime/):

  1. Directory: libs/parent/child/
  2. Project Name: parent-child (e.g., theme-system-theme-runtime)
  3. Import Path: @parent-child (matches project name)

Why? Our build system (path-resolver.js) reads the name from project.json for proper resolution.

🎯 Key Takeaways

  1. Unified Builder: All 42 libraries use the same custom builder
  2. Consistent Configuration: Standard tsconfig.lib.json with incremental: false
  3. Proper Naming: Nested libraries must include parent in project name
  4. Build Order: Always build libraries before apps (yarn build:libs:auto)
  5. Import Aliases: Always use @library-name aliases, never relative paths

🔧 Troubleshooting

"Cannot find module '@my-library'"

Cause: Library not built or incorrect path mapping

Solution:

# 1. Build the library
yarn nx build my-library

# 2. Verify path mapping in tsconfig.base.json
{
  "paths": {
    "@my-library": ["dist/libs/my-library/index"]
  }
}

# 3. For nested libraries, check project.json name
{
  "name": "parent-child"  // Must match directory structure
}

"Invalid TypeScript program emit for .tsbuildinfo"

Cause: incremental: true in tsconfig.lib.json

Solution:

{
  "compilerOptions": {
    "incremental": false  // Set to false
  }
}

"Static imports of lazy-loaded libraries are forbidden"

Cause: Using static import for @storage-system in example/demo code

Solution:

// ❌ Wrong: Static import
import { StorageService } from '@storage-system';

// ✅ Correct: Dynamic import
export async function example() {
  const { StorageService } = await import('@storage-system');
  // Use StorageService here
}

Build Takes Too Long

Cause: Building all 42 libraries individually

Solution:

# Use our optimized build script
yarn build:libs:auto

# This builds all libraries in parallel with smart caching
# Time: ~90 seconds for all 42 libraries

📚 Related Documentation


Last Updated: October 23, 2025
Status: All 42 libraries building successfully ✅