# Automatic Component Dependency Registration ## Overview The framework now automatically registers all component dependencies before rendering. When you bootstrap or create a component, all components listed in its `imports` array are recursively registered as native Web Components. ## How It Works ### Registration Flow ```typescript @Component({ selector: 'app-root', template: '', imports: [DashboardComponent], }) export class AppComponent {} // When bootstrapping: Core.bootstrap(AppComponent); ``` **Internal Process:** 1. `Core.bootstrap(AppComponent)` is called 2. `WebComponentFactory.createFromElement()` is invoked 3. `registerWithDependencies(appComponentInstance)` is called 4. Framework checks `imports: [DashboardComponent]` 5. Creates `DashboardComponent` instance via Injector 6. Recursively calls `registerWithDependencies(dashboardComponentInstance)` 7. Registers `DashboardComponent` as `` custom element 8. Registers `AppComponent` as `` custom element 9. Renders the template with all dependencies ready ### Code Implementation ```typescript // In WebComponentFactory static registerWithDependencies(component: IComponent): boolean { const imports = component._quarcComponent[0].imports || []; const injector = Injector.get(); // Register all imported components first for (const importItem of imports) { if (this.isComponentType(importItem)) { let componentInstance = injector.createInstance( importItem as Type ); if (!componentInstance._quarcComponent) { componentInstance = importItem as unknown as IComponent; } if (componentInstance._quarcComponent) { // Recursive call for nested dependencies this.registerWithDependencies(componentInstance); } } } // Finally register the parent component return this.tryRegister(component); } ``` ## Example: Multi-Level Dependencies ```typescript // Level 3: Icon Component (no dependencies) @Component({ selector: 'app-icon', template: '', }) export class IconComponent {} // Level 2: Button Component (depends on Icon) @Component({ selector: 'app-button', template: ` `, imports: [IconComponent], }) export class ButtonComponent {} // Level 1: Dashboard Component (depends on Button) @Component({ selector: 'dashboard', template: `

Dashboard

`, imports: [ButtonComponent], }) export class DashboardComponent {} // Level 0: Root Component (depends on Dashboard) @Component({ selector: 'app-root', template: '', imports: [DashboardComponent], }) export class AppComponent {} ``` **Registration Order:** 1. `IconComponent` → `` 2. `ButtonComponent` → `` 3. `DashboardComponent` → `` 4. `AppComponent` → `` ## Benefits ### ✅ No Manual Registration Before: ```typescript // Manual registration required WebComponentFactory.tryRegister(iconComponent); WebComponentFactory.tryRegister(buttonComponent); WebComponentFactory.tryRegister(dashboardComponent); Core.bootstrap(AppComponent); ``` After: ```typescript // Automatic registration Core.bootstrap(AppComponent); // All dependencies registered automatically ``` ### ✅ Correct Order Guaranteed The framework ensures components are registered in the correct dependency order, preventing errors where a parent tries to use an unregistered child component. ### ✅ Prevents Duplicate Registration The `tryRegister()` method checks if a component is already registered and returns `false` if it is, preventing duplicate registration errors. ### ✅ Supports Circular Dependencies If two components import each other (not recommended but possible), the registration system handles it gracefully by checking if a component is already registered before attempting to register it again. ### ✅ Works with Lazy Loading Components are only registered when they're actually needed, supporting lazy loading patterns: ```typescript // Only registers when loaded const lazyComponent = await import('./lazy.component'); WebComponentFactory.create(lazyComponent.LazyComponent); ``` ## Type Checking The `isComponentType()` helper ensures only valid components are processed: ```typescript private static isComponentType(item: any): boolean { // Check if it's a class constructor if (typeof item === 'function') { return true; } // Check if it's already an instance with metadata if (item && typeof item === 'object' && item._quarcComponent) { return true; } return false; } ``` ## Integration with Injector The framework uses the `Injector` to create component instances, which: - Resolves constructor dependencies - Caches instances for reuse - Supports dependency injection patterns ```typescript const injector = Injector.get(); let componentInstance = injector.createInstance( importItem as Type ); ``` ## Error Handling Registration errors are caught and logged without breaking the application: ```typescript try { customElements.define(tagName, WebComponentClass); this.registeredComponents.set(tagName, WebComponentClass); this.componentInstances.set(tagName, component); return true; } catch (error) { console.warn(`Failed to register component ${tagName}:`, error); return false; } ``` Common errors: - **Duplicate registration**: Component already registered (handled gracefully) - **Invalid tag name**: Tag name doesn't contain a hyphen (auto-converted) - **Constructor errors**: Component constructor throws an error (logged) ## Best Practices ### 1. Always Declare Imports ```typescript @Component({ selector: 'parent', template: '', imports: [ChildComponent], // ✅ Declared }) export class ParentComponent {} ``` ### 2. Avoid Circular Dependencies ```typescript // ❌ Avoid this @Component({ selector: 'comp-a', imports: [ComponentB], }) export class ComponentA {} @Component({ selector: 'comp-b', imports: [ComponentA], // Circular! }) export class ComponentB {} ``` ### 3. Use Lazy Loading for Large Dependencies ```typescript @Component({ selector: 'app-root', template: '', // Don't import heavy components here }) export class AppComponent { async loadHeavyComponent() { const { HeavyComponent } = await import('./heavy.component'); WebComponentFactory.create(HeavyComponent); } } ``` ## Debugging Enable console logging to see the registration flow: ```typescript // In WebComponentFactory.registerWithDependencies console.log(`Registering dependencies for: ${component._quarcComponent[0].selector}`); // In WebComponentFactory.tryRegister console.log(`Registering component: ${tagName}`); ``` ## Migration from Manual Registration If you have existing code with manual registration: **Before:** ```typescript WebComponentFactory.tryRegister(childComponent); WebComponentFactory.tryRegister(parentComponent); ``` **After:** ```typescript // Just use the parent, children are registered automatically WebComponentFactory.create(parentComponent); ``` Or simply: ```typescript Core.bootstrap(ParentComponent); ``` ## Summary The automatic dependency registration system: - ✅ Registers components in correct order - ✅ Handles nested dependencies recursively - ✅ Prevents duplicate registrations - ✅ Integrates with dependency injection - ✅ Provides error handling and logging - ✅ Supports lazy loading patterns - ✅ Simplifies component usage No manual registration needed - just declare your imports and bootstrap your app!