Import Exports Guide

Import/Export Strategy in NX Monorepos

๐Ÿ“ฆ Import/Export Strategy in NX Monorepos

This document explains the standardized index.ts pattern used across our NX workspace.

โš ๏ธ IMPORTANT: We have migrated from public-api.ts to index.ts for all libraries to maintain uniformity.


๐Ÿ”น index.ts - Two-Level Pattern

Level 1: Feature Folder Barrel Files

Level 2: Library Root Entry Point

๐Ÿ”น Standard Pattern

Use Case File Type Example Path
Feature re-exports index.ts src/lib/services/index.ts
Library public API index.ts src/index.ts

๐Ÿ”น Best Practices

  1. Consistency: Always use index.ts for both feature folders and library root entry points.
  2. Avoid Relative Paths: Never use ../../../libs/... - use libs/... instead.
  3. Type-Only Imports: Use import type for TypeScript types when possible.
  4. Entry Point: All libraries use src/index.ts as the entry point (no public-api.ts).

๐ŸŽฏ Example: Fixed Import in docs-angular

// Before (failing)
import type { LoadingOverlayConfig } from '@libs-foundational/core-models';

// After (working)
import type { LoadingOverlayConfig } from 'libs/core-models/src/lib/models/loading.types';

Consumers can then import:

import { SyncService } from '@storage-system';

โœ… Use index.ts freely in subfolders like models, services, or adapters to simplify imports.

3) Distinguishing Angular vs Non-Angular Libraries

Angular Libraries

Folder structure


libs/storage-system/ src/ angular/ services/ storage.service.ts index.ts signals/ storage.signal.ts index.ts index.ts ng-package.json project.json tsconfig.lib.json



### Example src/index.ts

```typescript
// libs/storage-system/src/index.ts
export * from './angular/services/storage.service';
export * from './angular/signals/storage.signal';

Correct ng-package.json for Angular libs

{
  "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
  "dest": "../../dist/storage-system",
  "lib": {
    "entryFile": "src/index.ts"
  }
}

Non-Angular Libraries (Plain TS)

Root entry file: src/index.ts

// libs/storage-system/src/index.ts
export * from './sync/adapters/file.adapter';
export * from './sync/models/sync.model';
export * from './sync/services';

This acts as the package entry point.

Folder structure

libs/storage-system/
  src/
    sync/
      adapters/
        file.adapter.ts
      models/
        sync.model.ts
      services/
        sync.service.ts
        index.ts
    index.ts
  project.json
  tsconfig.lib.json

Example index.ts


// libs/storage-system/src/index.ts
export * from './sync/adapters/file.adapter';
export * from './sync/models/sync.model';
export * from './sync/services';

๐Ÿ”ง TypeScript Configuration Requirements

Angular Libraries

Non-Angular Libraries

๐Ÿšจ Common Build Issues & Solutions

Issue 1: "Cannot find module '@storage-system'"

Cause: Missing path mappings in tsconfig.base.json Solution: Add proper path mappings:

{
  "compilerOptions": {
    "paths": {
      "@storage-system": ["libs/storage-system/src/index"],
      "@storage-system/*": ["libs/storage-system/src/*"]
    }
  }
}

Issue 2: "Dynamic imports are only supported when the '--module' flag is set to 'es2020'"

Cause: TypeScript target is too old (ES5) Solution: Update tsconfig.lib.json:

{
  "compilerOptions": {
    "target": "es2020",
    "lib": ["es2020", "dom"],
    "module": "esnext"
  }
}

Issue 3: "Decorators are not valid here"

Cause: Missing decorator support Solution: Add to tsconfig.lib.json:

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

Issue 4: "Entry point has a circular dependency on itself"

Cause: Library importing from itself Solution: Check imports - avoid circular dependencies by organizing code properly

Issue 5: "Cannot find module '@ux-portal'"

Cause: Missing dependency in project.json and package.json Solution:

  1. Add to project.json:
{
  "implicitDependencies": ["ux-portal", "storage-system"]
}
  1. Add to package.json:
{
  "peerDependencies": {
    "@ux-portal": "^1.0.0",
    "@storage-system": "^1.0.0"
  }
}

๐Ÿ”„ Converting Libraries Between Types

Converting Non-Angular โ†’ Angular Library

  1. Update project.json:

    {
      "targets": {
        "build": {
          "executor": "@nx/angular:ng-packagr-lite",
          "options": {
            "project": "libs/my-library/ng-package.json"
          }
        }
      },
      "tags": ["scope:my-scope", "type:angular"],
      "implicitDependencies": ["storage-system"]
    }
    
  2. Create ng-package.json:

    {
      "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
      "dest": "../../dist/libs/my-library",
      "lib": {
        "entryFile": "src/index.ts"
      }
    }
    
  3. Create src/index.ts:

    export * from './lib/adapters';
    export * from './lib/models';
    export * from './lib/services';
    
  4. Update tsconfig.base.json path mapping:

    {
      "paths": {
        "@my-library": ["libs/my-library/src/index"]
      }
    }
    

๐Ÿ“ File Organization Best Practices

When to Move Files Between Libraries

Example: Moving outbox.service.ts

// Before: In non-Angular library
import { signal, computed } from '@angular/core'; // โŒ Error

// After: In storage-system (Angular-aware library)
import { signal, computed } from '@angular/core'; // โœ… Works

๐Ÿงช Testing Build Issues

Debugging Steps

  1. Check dependencies: nx graph
  2. Clear cache: nx reset
  3. Build dependencies first: nx build storage-system --skip-nx-cache
  4. Check path mappings: Verify tsconfig.base.json
  5. Check file exports: Ensure src/index.ts exports what you need

Temporary Workarounds

If you need to get a build working quickly:

  1. Exclude problematic files in tsconfig.lib.json:

    {
      "exclude": [
        "**/*.spec.ts",
        "src/lib/directives/**/*",
        "src/lib/firebase/**/*"
      ]
    }
    
  2. Comment out exports in lib/index.ts:

    // export * from './directives';
    // export * from './firebase';
    export * from './services';
    

๐ŸŽฏ Summary


๐Ÿšจ HISTORICAL NOTE: Nested Library Build Issues (October 2025)

โœ… Resolved: Storage Library Consolidation

Previous Issue:

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

Historical Context:

  1. We used to have nested storage libraries: libs/storage/storage-angular, libs/storage/storage-core, etc.
  2. Had cross-library Angular imports that caused build issues
  3. Using @nx/angular:ng-packagr-lite executor couldn't resolve path aliases properly

Resolution (October 2025): All storage libraries have been consolidated into a single libs/storage-system library, eliminating nested structure issues.

What theme-system does (also nested but works):

โœ… Historical Solution (No Longer Needed)

Previous Workaround (Now Obsolete): We used custom build scripts to work around nested library issues. This is no longer necessary with the consolidated storage-system library.

Current Approach (Simplified):

// โœ… WORKS: Use unified storage-system library
import { StorageService, GgStorage, SyncChange, SyncCursor } from '@storage-system';
import { UxPortalService } from '@libs-ux/ux-portal';

// โŒ OLD (Don't use): Multiple storage libraries
import { UxPortalService } from 'libs/ux-portal/src/index';
import type { SyncChange } from 'libs/storage/storage-sync/src/index';
import type { GgStorage } from 'libs/storage/storage-core/src/index';

3. Simplify tsconfig.lib.json:

{
  "extends": "../../../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "../../dist/out-tsc",
    "declaration": true,
    "types": [],
    "skipLibCheck": true
  },
  "angularCompilerOptions": {
    "strictTemplates": true,
    "fullTemplateTypeCheck": true
  }
}

DO NOT override paths in library tsconfig - let it inherit from base.

Decision Matrix for Build Executors

Scenario Executor Import Style Notes
Simple Angular lib @nx/angular:ng-packagr-lite Aliases (@lib) Standard case
Nested, no cross-Angular imports @nx/angular:ng-packagr-lite Aliases (@lib) e.g., theme-system
Nested + cross-Angular imports Custom build script Direct paths e.g., storage-angular
TypeScript lib (no Angular) @nx/js:tsc Aliases (@lib) Standard case

Affected Libraries

Testing the Fix

# Clean build
yarn nx reset
yarn nx build storage-angular

# Should complete successfully with:
โœ… Building storage-angular with custom builder...
โœ… Compiling TypeScript...
โœ… Copying SCSS files...
โœ… Successfully ran target build