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?
- ✅ Ensures
experimentalDecoratorsandemitDecoratorMetadataare set correctly - ✅ Better error messages during compilation
- ✅ Consistent builds across all 42 libraries
- ✅ Proper handling of complex path mappings
- ✅ Integrated SCSS compilation with theme-system support
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)
- ❌ Mixed Executors: Libraries used different build systems (
@nx/js:tscvs@nx/angular:ng-packagr-lite) - ❌ Missing Decorator Support: Standard builders didn't set TypeScript decorator flags
- ❌ Inconsistent Builds: Different libraries built differently
- ✅ 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:
- Executor:
nx:run-commandswith custom builder - Command:
node tools/scripts/build/build-angular-library.js <library-name> - Build Output: ESM modules with TypeScript declarations
- Dependencies: Can import from any other library
- Use Case: Everything - UI components, services, utilities, type definitions
Examples in our codebase (42 total):
core-models- Shared type definitionsstorage-system- Unified storage systemtheme-system- Theme management (parent library)theme-system-theme-runtime- Runtime theme servicestheme-system-theme-styles- SCSS styles and variablesux-ui-core- Core UI componentsux-portal- Portal service and componentsflash-persistence- State management with persistenceeditor-ui- Editor interface components
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:
- Unified Builder: All libraries use the same custom builder
- Proper Decorators: TypeScript decorators are configured correctly
- Consistent Output: All libraries output to
dist/libs/ - Path Mappings:
tsconfig.base.jsonmaps 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 Success Rate: 100% (42/42)
- ✅ Unified Builder: All libraries use custom builder
- ✅ No Disabled Libraries: All build targets active
- ✅ Consistent Configuration: Standard tsconfig patterns
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/):
- Directory:
libs/parent/child/ - Project Name:
parent-child(e.g.,theme-system-theme-runtime) - 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
- Unified Builder: All 42 libraries use the same custom builder
- Consistent Configuration: Standard
tsconfig.lib.jsonwithincremental: false - Proper Naming: Nested libraries must include parent in project name
- Build Order: Always build libraries before apps (
yarn build:libs:auto) - Import Aliases: Always use
@library-namealiases, 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 ✅