324 lines
7.7 KiB
Markdown
324 lines
7.7 KiB
Markdown
# Lazy Loading Architecture
|
|
|
|
The Core framework now uses WebComponents with lazy loading support based on component imports.
|
|
|
|
## Key Concepts
|
|
|
|
### 1. Component Registry
|
|
|
|
A centralized registry that tracks all components, their dependencies, and loading status.
|
|
|
|
```typescript
|
|
const registry = Core.getRegistry();
|
|
|
|
// Check if component is loaded
|
|
const isLoaded = registry.isLoaded(MyComponent);
|
|
|
|
// Get component metadata
|
|
const metadata = registry.getMetadata(MyComponent);
|
|
|
|
// Get all dependencies
|
|
const deps = registry.getAllDependencies(MainComponent);
|
|
```
|
|
|
|
### 2. Main Component
|
|
|
|
The main component is set during bootstrap and stored as a static member.
|
|
|
|
```typescript
|
|
Core.bootstrap(AppComponent);
|
|
|
|
// Access main component type
|
|
const mainComponentType = Core.MainComponent;
|
|
|
|
// Access main WebComponent instance
|
|
const mainWebComponent = Core.getMainWebComponent();
|
|
```
|
|
|
|
### 3. Component Imports
|
|
|
|
Components declare their dependencies using the `imports` property.
|
|
|
|
```typescript
|
|
export class AppComponent implements IComponent {
|
|
selector = 'app-root';
|
|
template = '<div>App</div>';
|
|
imports = [HeaderComponent, FooterComponent, SidebarComponent];
|
|
}
|
|
```
|
|
|
|
## Bootstrap Process
|
|
|
|
When `Core.bootstrap()` is called:
|
|
|
|
1. **Set Main Component** - Stores the component type in `Core.MainComponent`
|
|
2. **Register Component** - Adds the main component to the registry
|
|
3. **Resolve Dependencies** - Recursively finds all dependencies from `imports`
|
|
4. **Preload Dependencies** - Creates instances of all dependencies (but doesn't render them)
|
|
5. **Create WebComponent** - Creates and renders the main component
|
|
6. **Mark as Loaded** - Updates registry to show main component is loaded
|
|
|
|
```typescript
|
|
// Bootstrap flow
|
|
Core.bootstrap(AppComponent, element);
|
|
// ↓
|
|
// Core.MainComponent = AppComponent
|
|
// ↓
|
|
// Registry: [AppComponent, HeaderComponent, FooterComponent, ...]
|
|
// ↓
|
|
// Only AppComponent is rendered (loaded: true)
|
|
// Dependencies are preloaded (loaded: false)
|
|
```
|
|
|
|
## Lazy Loading Components
|
|
|
|
Components are lazy loaded when explicitly requested:
|
|
|
|
```typescript
|
|
// Load a component on demand
|
|
const webComponent = Core.loadComponent(DashboardComponent, element);
|
|
|
|
// Component is now loaded and rendered
|
|
const isLoaded = Core.getRegistry().isLoaded(DashboardComponent);
|
|
// → true
|
|
```
|
|
|
|
## Component Lifecycle
|
|
|
|
### Preloaded (Not Rendered)
|
|
|
|
```typescript
|
|
{
|
|
type: HeaderComponent,
|
|
instance: headerInstance, // ✓ Created
|
|
webComponent: undefined, // ✗ Not rendered
|
|
loaded: false, // ✗ Not loaded
|
|
dependencies: []
|
|
}
|
|
```
|
|
|
|
### Loaded (Rendered)
|
|
|
|
```typescript
|
|
{
|
|
type: HeaderComponent,
|
|
instance: headerInstance, // ✓ Created
|
|
webComponent: webComponent, // ✓ Rendered
|
|
loaded: true, // ✓ Loaded
|
|
dependencies: []
|
|
}
|
|
```
|
|
|
|
## Complete Example
|
|
|
|
### 1. Define Components
|
|
|
|
```typescript
|
|
// header.component.ts
|
|
export class HeaderComponent implements IComponent {
|
|
selector = 'app-header';
|
|
template = '<header>Header</header>';
|
|
style = 'header { background: #333; }';
|
|
}
|
|
|
|
// sidebar.component.ts
|
|
export class SidebarComponent implements IComponent {
|
|
selector = 'app-sidebar';
|
|
template = '<aside>Sidebar</aside>';
|
|
style = 'aside { width: 200px; }';
|
|
}
|
|
|
|
// dashboard.component.ts
|
|
export class DashboardComponent implements IComponent {
|
|
selector = 'app-dashboard';
|
|
template = '<div>Dashboard</div>';
|
|
imports = []; // No dependencies
|
|
}
|
|
|
|
// app.component.ts
|
|
export class AppComponent implements IComponent {
|
|
selector = 'app-root';
|
|
template = `
|
|
<div class="app">
|
|
<app-header></app-header>
|
|
<app-sidebar></app-sidebar>
|
|
<main id="content"></main>
|
|
</div>
|
|
`;
|
|
imports = [HeaderComponent, SidebarComponent];
|
|
// DashboardComponent is NOT imported - will be lazy loaded
|
|
}
|
|
```
|
|
|
|
### 2. Bootstrap Application
|
|
|
|
```typescript
|
|
// main.ts
|
|
import { Core } from '@nglite/core/core/main';
|
|
import { AppComponent } from './app.component';
|
|
|
|
// Bootstrap - loads AppComponent + its imports
|
|
const core = Core.bootstrap(AppComponent);
|
|
|
|
// At this point:
|
|
// - AppComponent: loaded (rendered)
|
|
// - HeaderComponent: preloaded (not rendered)
|
|
// - SidebarComponent: preloaded (not rendered)
|
|
// - DashboardComponent: not loaded
|
|
|
|
console.log('Main component:', Core.MainComponent);
|
|
// → AppComponent
|
|
|
|
const registry = Core.getRegistry();
|
|
console.log('Is HeaderComponent loaded?', registry.isLoaded(HeaderComponent));
|
|
// → false (preloaded but not rendered)
|
|
```
|
|
|
|
### 3. Lazy Load Components
|
|
|
|
```typescript
|
|
// Later, when user navigates to dashboard
|
|
const contentElement = document.getElementById('content');
|
|
|
|
if (contentElement) {
|
|
// Lazy load and render DashboardComponent
|
|
const dashboardWC = Core.loadComponent(DashboardComponent, contentElement);
|
|
|
|
// Now it's loaded
|
|
console.log('Is DashboardComponent loaded?',
|
|
Core.getRegistry().isLoaded(DashboardComponent));
|
|
// → true
|
|
|
|
// Access the WebComponent
|
|
const children = dashboardWC.getChildElements();
|
|
const attributes = dashboardWC.getAttributes();
|
|
}
|
|
```
|
|
|
|
### 4. Load Preloaded Components
|
|
|
|
```typescript
|
|
// Render a preloaded component
|
|
const headerElement = document.querySelector('app-header');
|
|
|
|
if (headerElement) {
|
|
const headerWC = Core.loadComponent(HeaderComponent, headerElement);
|
|
|
|
// Now it's rendered
|
|
console.log('Is HeaderComponent loaded?',
|
|
Core.getRegistry().isLoaded(HeaderComponent));
|
|
// → true
|
|
}
|
|
```
|
|
|
|
## API Reference
|
|
|
|
### Core Static Methods
|
|
|
|
#### `Core.bootstrap(component, element?): Core`
|
|
|
|
Bootstraps the application with the main component.
|
|
|
|
```typescript
|
|
const core = Core.bootstrap(AppComponent);
|
|
```
|
|
|
|
#### `Core.MainComponent: Type<IComponent> | null`
|
|
|
|
The main component type.
|
|
|
|
```typescript
|
|
if (Core.MainComponent === AppComponent) {
|
|
console.log('App is bootstrapped');
|
|
}
|
|
```
|
|
|
|
#### `Core.getMainWebComponent(): WebComponent | null`
|
|
|
|
Gets the main component's WebComponent instance.
|
|
|
|
```typescript
|
|
const mainWC = Core.getMainWebComponent();
|
|
if (mainWC) {
|
|
const children = mainWC.getChildElements();
|
|
}
|
|
```
|
|
|
|
#### `Core.loadComponent(componentType, element?): WebComponent`
|
|
|
|
Loads and renders a component.
|
|
|
|
```typescript
|
|
const wc = Core.loadComponent(MyComponent, element);
|
|
```
|
|
|
|
#### `Core.getRegistry(): ComponentRegistry`
|
|
|
|
Gets the component registry.
|
|
|
|
```typescript
|
|
const registry = Core.getRegistry();
|
|
const all = registry.getAll();
|
|
```
|
|
|
|
### ComponentRegistry Methods
|
|
|
|
#### `register(type, instance): void`
|
|
|
|
Registers a component instance.
|
|
|
|
#### `markAsLoaded(type, webComponent): void`
|
|
|
|
Marks a component as loaded.
|
|
|
|
#### `isLoaded(type): boolean`
|
|
|
|
Checks if a component is loaded.
|
|
|
|
#### `getMetadata(type): ComponentMetadata | undefined`
|
|
|
|
Gets component metadata.
|
|
|
|
#### `getBySelector(selector): ComponentMetadata | undefined`
|
|
|
|
Gets component by selector.
|
|
|
|
#### `getWebComponent(type): WebComponent | undefined`
|
|
|
|
Gets the WebComponent instance.
|
|
|
|
#### `getDependencies(type): Type<IComponent>[]`
|
|
|
|
Gets direct dependencies.
|
|
|
|
#### `getAllDependencies(type): Type<IComponent>[]`
|
|
|
|
Gets all dependencies recursively.
|
|
|
|
#### `getAll(): ComponentMetadata[]`
|
|
|
|
Gets all registered components.
|
|
|
|
## Benefits
|
|
|
|
1. **Faster Initial Load** - Only main component and its dependencies are rendered
|
|
2. **Memory Efficient** - Components are preloaded but not rendered until needed
|
|
3. **Dependency Tracking** - Automatic resolution of component dependencies
|
|
4. **Lazy Loading** - Load components on demand
|
|
5. **Centralized Registry** - Single source of truth for component state
|
|
|
|
## Performance
|
|
|
|
```
|
|
Without Lazy Loading:
|
|
- Load all components: 100ms
|
|
- Render all components: 200ms
|
|
- Total: 300ms
|
|
|
|
With Lazy Loading:
|
|
- Load main + dependencies: 50ms
|
|
- Render main component: 50ms
|
|
- Total initial: 100ms
|
|
- Lazy load on demand: 20ms per component
|
|
```
|