Apps Imports
Ecosistema completo para organización y gestión de contenido con interfaces espaciales
App Imports Guide
Complete guide to import strategies, path aliases, barrel exports, and Angular static analysis requirements for NX applications.
Import Strategy Overview
In our NX monorepo, apps import libraries using path aliases that resolve to source code, not built distributions. Angular's build system handles bundling automatically.
// ✅ Correct - Import from alias (resolves to source)
import { UxPortalService } from '@libs-ux/ux-portal';
import { StorageService } from '@storage-system';
// ❌ Wrong - Don't import from dist
import { UxPortalService } from '../../dist/libs/ux-portal';
// ❌ Wrong - Don't use relative paths across libraries
import { StorageService } from '../../libs/storage-system/src/lib/storage.service';
Path Alias Configuration
Workspace-Level Aliases (tsconfig.base.json)
Define all library aliases at the workspace root:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
// Root alias - imports from barrel (index.ts)
"@ux-portal": ["libs/ux-portal/src/index"],
// Wildcard alias - allows deep imports
"@ux-portal/*": ["libs/ux-portal/src/*"],
"@storage-system": ["libs/storage-system/src/index"],
"@storage-system/*": ["libs/storage-system/src/*"],
"@ux-ui-core": ["libs/ux-ui-core/src/index"],
"@ux-ui-core/*": ["libs/ux-ui-core/src/*"]
}
}
}
Why both aliases?
- Root alias (
@library) - For barrel imports (services, utilities) - Wildcard alias (
@library/*) - For deep imports (components for static analysis)
App Configuration
Apps inherit these aliases through extends:
// apps/my-app/tsconfig.json
{
"extends": "../../tsconfig.base.json",
// Paths are automatically available - don't redefine them!
}
Library Barrel Exports
Standard Barrel Pattern (src/index.ts)
Each library should export its public API from src/index.ts:
// libs/ux-portal/src/index.ts
// Services
export { UxPortalService } from './lib/services/portal.service';
export { UxPortalConfig } from './lib/models/portal-config';
// Components (for static analysis)
export { UxModalComponent } from './lib/components/modal/modal.component';
export { UxDrawerComponent } from './lib/components/drawer/drawer.component';
// Types
export * from './lib/models';
Guidelines:
- ✅ Export concrete component classes (not just type-only exports)
- ✅ Keep barrel in sync with actual exports
- ✅ Export from specific files, not re-exporting barrels
- ❌ Don't export symbols that don't exist
Angular Static Analysis
The Challenge
Angular's compiler requires imports in @Component({ imports: [...] }) to be statically analyzable. This means Angular must determine the exact component class at compile time.
Barrel Imports (Services, Utilities)
Use barrel imports for services, utilities, and models:
// ✅ Perfect for services
import { UxPortalService, UxPortalConfig } from '@libs-ux/ux-portal';
import { StorageService } from '@storage-system';
@Component({
// Services work fine from barrels
})
export class MyComponent {
private portal = inject(UxPortalService);
private storage = inject(StorageService);
}
Component Imports (Static Analysis)
Two approaches for standalone components:
Approach 1: Barrel Import (If Exported Properly)
// ✅ Works if component is exported from barrel
import { UxTabsComponent, UxTabComponent } from '@ux-ui-core';
@Component({
standalone: true,
imports: [UxTabsComponent, UxTabComponent]
})
export class MyComponent {}
Approach 2: Deep Import (Always Works)
// ✅ Always works - direct file import
import { UxTabsComponent } from '@ux-ui-core/lib/tabs/tabs.component';
import { UxTabComponent } from '@ux-ui-core/lib/tabs/tab.component';
@Component({
standalone: true,
imports: [UxTabsComponent, UxTabComponent]
})
export class MyComponent {}
When to use which:
- Barrel imports - If library exports components properly and you prefer cleaner imports
- Deep imports - If you get static analysis errors or want guaranteed compatibility
Import Patterns by Use Case
Services and Dependency Injection
// Always use barrel imports
import { ThemeService } from '@theme-system';
import { StorageService } from '@storage-system';
import { LogService } from '@log-system';
@Component({
// ...
})
export class MyComponent {
private theme = inject(ThemeService);
private storage = inject(StorageService);
private logger = inject(LogService);
}
Standalone Components
// Option 1: Barrel (if available)
import { UxButtonComponent, UxCardComponent } from '@ux-ui-core';
// Option 2: Deep (always works)
import { UxButtonComponent } from '@ux-ui-core/lib/button/button.component';
import { UxCardComponent } from '@ux-ui-core/lib/card/card.component';
@Component({
standalone: true,
imports: [UxButtonComponent, UxCardComponent]
})
export class MyComponent {}
Types and Interfaces
// Use barrel imports for types
import type { SafeAny, DeepPartial } from '@libs-foundational/core-models';
import type { ThemeConfig, ThemeMode } from '@theme-system';
import type { StorageOptions } from '@storage-system';
// Type-only imports for optimization
import type { ComponentType } from '@angular/cdk/portal';
Utilities and Helper Functions
// Barrel imports work perfectly
import { deepClone, isEqual } from '@utilities';
import { formatDate, parseDate } from '@date-utils';
import { validateEmail, sanitizeInput } from '@validators';
Common Import Errors
❌ "Cannot find module '@library'"
Causes:
- Library not built
- Alias not in
tsconfig.base.json - Missing
src/**/*.tsin app'stsconfig.app.json
Solutions:
# 1. Build the library
npx nx build library-name
# 2. Add to tsconfig.base.json
{
"paths": {
"@library-name": ["libs/library-name/src/index"],
"@library-name/*": ["libs/library-name/src/*"]
}
}
# 3. Update tsconfig.app.json
{
"include": ["src/**/*.ts", "src/**/*.d.ts"]
}
# 4. Restart TypeScript server
❌ "'imports' must be an array... Value could not be determined statically"
Cause: Angular can't analyze the component import.
Solution: Use deep import:
// ❌ Might fail if barrel is complex
import { MyComponent } from '@my-lib';
// ✅ Always works
import { MyComponent } from '@my-lib/lib/my-component/my.component';
❌ "Circular dependency detected"
Cause: Barrel re-exports creating loops.
Solution: Use direct imports or fix barrel structure:
// ❌ Circular through barrel
import { ServiceA } from '@my-lib';
import { ServiceB } from '@my-lib';
// ✅ Direct imports break the cycle
import { ServiceA } from '@my-lib/lib/service-a';
import { ServiceB } from '@my-lib/lib/service-b';
Adding New Library Imports
Checklist
When adding a new library to import from:
- Add path aliases to
tsconfig.base.json:
{
"@new-lib": ["libs/new-lib/src/index"],
"@new-lib/*": ["libs/new-lib/src/*"]
}
- Create barrel export (
libs/new-lib/src/index.ts):
export { MyService } from './lib/my.service';
export { MyComponent } from './lib/my.component';
- Build the library:
npx nx build new-lib
- Import in your app:
import { MyService } from '@new-lib';
- Restart TypeScript server in your IDE
Best Practices
DO ✅
- ✅ Use path aliases for all library imports
- ✅ Import from source (
libs/...) notdist/libs/... - ✅ Define both root and wildcard aliases in
tsconfig.base.json - ✅ Export components properly in library barrels
- ✅ Use deep imports when static analysis requires it
- ✅ Build libraries before importing them
- ✅ Use type-only imports when possible for tree-shaking
DON'T ❌
- ❌ Don't use relative paths across libraries
- ❌ Don't import from dist folders
- ❌ Don't redefine aliases in app configs
- ❌ Don't mix barrel and deep imports for the same component
- ❌ Don't export non-existent symbols in barrels
- ❌ Don't create circular dependencies through barrels
Import Organization
Recommended Import Order
// 1. Angular core
import { Component, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
// 2. Third-party libraries
import { Observable } from 'rxjs';
import { map, filter } from 'rxjs/operators';
// 3. Workspace libraries (alphabetical)
import { LogService } from '@log-system';
import { StorageService } from '@storage-system';
import { ThemeService } from '@theme-system';
// 4. Workspace UI components (alphabetical)
import { UxButtonComponent } from '@ux-ui-core';
import { UxCardComponent } from '@ux-ui-core';
// 5. Local imports (relative paths)
import { MyLocalService } from './services/my-local.service';
import type { MyLocalType } from './models/my-local.model';
@Component({
// ...
})
export class MyComponent {}
TypeScript Import Syntax
Named Imports
// Multiple named exports
import { ServiceA, ServiceB, TypeC } from '@my-lib';
// Renamed imports
import { ServiceA as MyServiceA } from '@my-lib';
Type-Only Imports
// Type-only (better tree-shaking)
import type { MyType, MyInterface } from '@my-lib';
// Mixed (not recommended)
import { MyService, type MyType } from '@my-lib';
Namespace Imports
// Import entire namespace (use sparingly)
import * as MyLib from '@my-lib';
// Usage
const service = new MyLib.MyService();
Related Documentation
- App Configuration - TypeScript and build configuration
- Library Structure - How libraries are organized
- NX Workspace - Monorepo architecture
Key Takeaway: Apps import from library source code (libs/...) using path aliases, and Angular's build system handles everything else automatically!