{"id":50547945,"url":"https://github.com/caballeroluis/ngrx-separate-state-by-lazy-module-example","last_synced_at":"2026-06-04T00:30:24.988Z","repository":{"id":343255008,"uuid":"863488861","full_name":"caballeroluis/ngrx-separate-state-by-lazy-module-example","owner":"caballeroluis","description":"Arquitectura Enterprise (Angular 14): Estructura Modular y estrategia \"Double-Lazy\" para liberar la red y optimizar memoria mediante carga selectiva de JS y NgRx. Optimizado para datos masivos bajo demanda, persistencia automática en LocalStorage y monitoreo con Redux DevTools. Máximo rendimiento","archived":false,"fork":false,"pushed_at":"2026-03-09T14:50:00.000Z","size":5535,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-03-09T19:30:34.553Z","etag":null,"topics":["angular","angular-13","enterprise-architecture","lazy-loading","ngrx-effects","ngrx-entity","ngrx-store","ngrx-store-localstorage","performance-optimization"],"latest_commit_sha":null,"homepage":"https://stackblitz.com/~/github.com/caballeroluis/ngrx-separate-state-by-lazy-module-example","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/caballeroluis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-09-26T11:38:27.000Z","updated_at":"2026-03-09T14:50:05.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/caballeroluis/ngrx-separate-state-by-lazy-module-example","commit_stats":null,"previous_names":["caballeroluis/ngrx-separate-state-by-lazy-module-example"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/caballeroluis/ngrx-separate-state-by-lazy-module-example","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/caballeroluis%2Fngrx-separate-state-by-lazy-module-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/caballeroluis%2Fngrx-separate-state-by-lazy-module-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/caballeroluis%2Fngrx-separate-state-by-lazy-module-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/caballeroluis%2Fngrx-separate-state-by-lazy-module-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/caballeroluis","download_url":"https://codeload.github.com/caballeroluis/ngrx-separate-state-by-lazy-module-example/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/caballeroluis%2Fngrx-separate-state-by-lazy-module-example/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33886153,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-03T02:00:06.370Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","angular-13","enterprise-architecture","lazy-loading","ngrx-effects","ngrx-entity","ngrx-store","ngrx-store-localstorage","performance-optimization"],"created_at":"2026-06-04T00:30:24.211Z","updated_at":"2026-06-04T00:30:24.982Z","avatar_url":"https://github.com/caballeroluis.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🏛️ Enterprise Angular: Orquestación de Estado Segmentado (NgRx)\n\n[![Angular](https://img.shields.io/badge/Angular-DD0031?logo=angular\u0026logoColor=white)](https://angular.io/docs)\n[![NgRx](https://img.shields.io/badge/NgRx-BA2BD2?logo=ngrx\u0026logoColor=white)](https://ngrx.io/guide/store)\n[![Performance](https://img.shields.io/badge/Performance-00C853?logo=speedtest\u0026logoColor=white)](https://img.shields.io/badge/Performance-00C853?logo=speedtest\u0026logoColor=white)\n[![Architecture](https://img.shields.io/badge/Architecture-2962FF?logo=blueprint\u0026logoColor=white)](https://img.shields.io/badge/Architecture-2962FF?logo=blueprint\u0026logoColor=white)\n[![Open in StackBlitz](https://img.shields.io/badge/Open%20in%20StackBlitz-1269D3?logo=stackblitz\u0026logoColor=white)](https://stackblitz.com/~/github.com/caballeroluis/ngrx-separate-state-by-lazy-module-example)\n\nEste repositorio documenta el blueprint de arquitectura que diseñé para enfrentar un reto real en el sector financiero. Aquí detallo las decisiones estratégicas tomadas ante restricciones técnicas severas y requisitos de alta escalabilidad.\n\n## 📜 1. El Escenario Inicial: Incertidumbre y Restricciones\nAl inicio del proyecto, me enfrenté a un entorno con tres condicionantes críticos:\n\n*   **Legacy por Normativa:** Entorno anclado en Angular 13 por políticas corporativas.\n*   **Requisitos Volátiles:** No se habían definido las librerías de UI finales ni cómo los usuarios construirían sus consultas complejas (Queries).\n*   **Carga Crítica:** El sistema debía manejar volúmenes ingentes de datos y garantizar una carga casi instantánea.\n\n\u003e  [!NOTE]\n\u003e **Versión de Referencia: Angular 14**\n\u003e Aunque el reto real nació en la v13, este repositorio ha sido actualizado a **Angular 14**. He elegido esta versión específicamente por ser el \"techo tecnológico\" de la arquitectura basada en módulos. Es la versión más estable y potente para sistemas que requieren un control estricto del estado antes de la transición masiva a *Standalone Components* introducida en la v15.\n\u003e \n\n## 💡 2. La Estrategia: \"Cimientos antes que Carrocería\"\nAnticipando un crecimiento masivo, tomé decisiones para blindar el núcleo del negocio:\n\n*   **A. NgRx como Única Fuente de Verdad:** Implementé NgRx para garantizar que el flujo de datos fuera predecible. Si mañana cambiaba la librería de componentes, la lógica de negocio permanecería intacta.\n*   **B. Estrategia \"Double-Lazy\" (Rendimiento Extremo):** Diseñé un sistema donde tanto el código JS como el Estado Redux (reducers/effects) solo se inyectan en el Store al activar la ruta, manteniendo la memoria limpia.\n*   **C. Caché Reactiva (Local Storage):** Dada la complejidad de las consultas, implementé hidratación automática con `ngrx-store-localstorage`. Si el usuario refresca la página, su contexto de datos se recupera al instante sin re-ejecutar peticiones pesadas al servidor.\n\n## 🛠️ 3. ¿Para qué te sirve este repositorio?\nSi eres desarrollador Angular, este proyecto te resultará útil como referencia técnica para implementar:\n\n1.  **Un Lazy Loading Especial:** No solo fragmentamos la carga de código JS; aplicamos una fragmentación de carga de datos masiva.\n2.  **Persistencia Automatizada:** Ejemplo práctico de cómo usar `ngrx-store-localstorage` para cachear segmentos específicos del estado.\n3.  **Rendimiento O(1):** Uso de `@ngrx/entity` para manejar miles de registros sin degradar la UI (manteniendo 60fps).\n\n## 🌐 Live Demo \u0026 Source\n\nExplora la demo interactiva directamente en StackBlitz para ver la arquitectura en acción:\n\n👉 **[Live Demo on StackBlitz](https://stackblitz.com/~/github.com/caballeroluis/ngrx-separate-state-by-lazy-module-example)**\n\n---\n\n# 📸 Recorrido Técnico: Arquitectura en Acción\n\n## Screenshots\n\n![1](https://github.com/caballeroluis/ngrx-separate-state-by-lazy-module-example/blob/master/src/assets/img/1.png?raw=true)\n1. **Pantalla Inicial**: Muestra la vista principal al cargar la aplicación. El Store se inicializa únicamente con el estado base (`app`), optimizando la memoria inicial.\n\n![2](https://github.com/caballeroluis/ngrx-separate-state-by-lazy-module-example/blob/master/src/assets/img/2.png?raw=true)\n2. **Gestión de Identidad**: Proceso de inicio de sesión donde la información de autenticación se sincroniza automáticamente en el almacenamiento de Redux y se persiste gracias al MetaReducer global.\n\n![3](https://github.com/caballeroluis/ngrx-separate-state-by-lazy-module-example/blob/master/src/assets/img/3.png?raw=true)\n3. **Carga del Módulo `Weather`**: Demostración de **Lazy Loading**. El archivo JS del módulo y su lógica de Redux asociada se descargan solo al navegar a esta ruta, inyectando el estado de forma dinámica.\n\n![4](https://github.com/caballeroluis/ngrx-separate-state-by-lazy-module-example/blob/master/src/assets/img/4.png?raw=true)\n4. **Carga del Módulo `List`**: Al acceder a la lista, se activa el fragmento de estado `list`. Se observa cómo la arquitectura escala horizontalmente descargando solo los recursos necesarios.\n\n![5](https://github.com/caballeroluis/ngrx-separate-state-by-lazy-module-example/blob/master/src/assets/img/5.png?raw=true)\n5. **Gestión de Productos**: Demostración de integridad en el manejo de entidades dentro de la lista de la compra, con actualizaciones síncronas en el Store persistente.\n\n---\n\n## 🏗️ Implementación: Cómo añadir un Nuevo Módulo\n\nPara añadir un nuevo módulo a esta aplicación, es necesario realizar varios cambios estratégicos para integrarlo correctamente en la estructura existente, asegurando que tanto el código como el estado se carguen de forma perezosa (**Double-Lazy Architecture**).\n\n![6](https://github.com/caballeroluis/ngrx-separate-state-by-lazy-module-example/blob/master/src/assets/img/6.png?raw=true)\n\nEste proyecto destaca por una arquitectura de **Persistencia Selectiva**. A diferencia de las implementaciones estándar de NgRx donde todo el almacenamiento se procesa al inicio, aquí tanto el código (JS) como la hidratación de datos del LocalStorage ocurren de forma bajo demanda.\n\n### 1. Importar el Nuevo Módulo y Configurar Persistencia\n\nDebes registrar la lógica del nuevo módulo en tu `AppModule`. Como indica la **primera flecha**, esto se hace modificando la función `localStorageSyncReducer`. Al añadir la clave `'new'` al array de keys, el sistema queda preparado para vigilar esa parcela de datos, pero no la cargará en memoria hasta que el módulo sea instanciado.\n\n```typescript\nexport function localStorageSyncReducer(reducer: any): any {\n  // Se registra la clave para que la persistencia se active bajo demanda\n  return localStorageSync({\n    keys: ['app', 'weather', 'list', 'new'],\n    rehydrate: true\n  })(reducer);\n}\n```\n\n### 2. Configuración de Routing Dinámico (Lazy Loading)\n\nPara cumplir con la carga perezosa de la interfaz, configura la ruta en `app-routing.module.ts` usando importación dinámica. Esto evita que el navegador descargue el código del módulo hasta que el usuario navegue a la ruta correspondiente:\n\n```typescript\n{\n  path: 'new',\n  loadChildren: () =\u003e\n    import('./modules/new/new.module').then(m =\u003e m.NewModule)\n}\n```\n\nCon esta configuración Angular descargará el bundle del módulo **solo cuando la ruta sea activada**.\n\n### 3. Inyección del Feature Store\n\nFinalmente, en el nuevo `new.module.ts`, inyecta el estado y los efectos asociados. Al usar `forFeature`, el Store de NgRx inyecta dinámicamente el reducer en el Store global **solo cuando el módulo se carga**, activando también la hidratación desde el LocalStorage:\n\n```typescript\n@NgModule({\n  imports: [\n    CommonModule,\n\n    // El estado se inyecta dinámicamente al cargar el módulo\n    StoreModule.forFeature('new', newReducer),\n\n    // Los efectos se registran solo cuando la feature está activa\n    EffectsModule.forFeature([NewEffects])\n  ]\n})\nexport class NewModule {}\n```\n\n---\n\n### 📊 Análisis de Rendimiento: Estándar vs. Segmentado\n\nA continuación, se detalla cómo esta arquitectura impacta positivamente en el consumo de recursos del cliente:\n\n\n| Característica | NgRx Estándar (Monolítico) | Arquitectura Segmentada (Este Proyecto) | Beneficio |\n| :--- | :--- | :--- | :--- |\n| **Carga de JS Inicial** | Todo el código de negocio se descarga al inicio. | Solo se descarga el Core del sistema. | **Reducción de Bundle inicial.** |\n| **Memoria RAM (Store)** | El estado global crece linealmente con cada módulo. | El Store solo crece con los módulos visitados. | **Ahorro de memoria en sesiones largas.** |\n| **Hidratación (Storage)** | Se procesan todas las claves del LocalStorage al arrancar. | Solo se hidrata la \"parcela\" de datos del módulo activo. | **TBT (Total Blocking Time) reducido.** |\n| **Escalabilidad** | El rendimiento se degrada al añadir 50+ módulos. | Rendimiento constante ($O(1)$) independientemente del número de módulos. | **Escalabilidad Horizontal.** |\n\n\u003e [!TIP]\n\u003e **Conclusión técnica:** Mientras que una arquitectura estándar penaliza al usuario desde el segundo 0, este modelo garantiza que el coste de computación sea proporcional al uso real que se hace de la aplicación.\n\n---\n\n## 🚀 Guía de Desarrollo y Operaciones CLI\n\n### 🖥️ Servidor de Desarrollo\nEjecuta `ng serve` para iniciar un servidor local. Navega a `http://localhost:4200/`. La aplicación se recargará automáticamente ante cualquier cambio.\n\n### 🏗️ Build y Despliegue\nEjecuta `ng build` para compilar el proyecto. Los artefactos listos para producción se guardarán en el directorio `dist/`.\n\n### 📦 Generación de Código\nUsa el Angular CLI para mantener la consistencia arquitectónica:\n*   **Componente:** `ng generate component nombre-componente`\n*   **Módulo:** `ng generate module nombre-modulo --route nombre-ruta --module app-routing.module`\n\n### 🧹 Cómo Limpiar el Local Storage (Reset de Estado)\nAl usar `ngrx-store-localstorage`, es posible que necesites resetear el estado durante las pruebas:\n1. Abre DevTools (`F12`).\n2. Ve a la pestaña **Aplicación** (Chrome) o **Almacenamiento** (Firefox).\n3. En **Local Storage**, localiza `http://localhost:4200/` y haz clic en **Clear All / Eliminar todo**.\n\n---\n\n*\"Diseñado para la escalabilidad. Optimizado para el rendimiento.\"*\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcaballeroluis%2Fngrx-separate-state-by-lazy-module-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcaballeroluis%2Fngrx-separate-state-by-lazy-module-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcaballeroluis%2Fngrx-separate-state-by-lazy-module-example/lists"}