Adapter de Angular
El adapter de Angular soporta Angular 14+ en tres formas: apps con NgModule,
componentes standalone y Angular Elements. Solo una de ellas funciona dentro del
Shadow DOM, que es el modo de aislamiento por defecto de Wu, así que empieza por
registerStandalone().
npm install wu-framework @angular/core @angular/platform-browser zone.jsInicio rápido — componentes standalone
Sección titulada «Inicio rápido — componentes standalone»import 'zone.js';import '@angular/compiler'; // modo JIT — no hace falta el plugin AOTimport { createApplication } from '@angular/platform-browser';import { createComponent, provideZoneChangeDetection } from '@angular/core';import { wuAngular } from 'wu-framework/adapters/angular';import { AppComponent } from './app/app.component';
wuAngular.registerStandalone('dashboard', AppComponent, { createApplication, // pásale las APIs de Angular — ver abajo createComponent, provideZoneChangeDetection,});registerStandalone(appName, RootComponent, options)
Sección titulada «registerStandalone(appName, RootComponent, options)»El punto de entrada recomendado. Usa createApplication + createComponent con
un hostElement explícito, lo que funciona en todas partes, incluido el
Shadow DOM.
| Opción | Tipo | Por defecto | Notas |
|---|---|---|---|
appConfig |
ApplicationConfig |
{} |
Configuración estándar de aplicación Angular; sus providers se fusionan. |
createApplication |
function |
null |
De @angular/platform-browser. Muy recomendable. |
createComponent |
function |
null |
De @angular/core. |
provideZoneChangeDetection |
function |
null |
De @angular/core. Cuando está presente, el adapter añade provideZoneChangeDetection({ eventCoalescing: true }) a los providers. |
standalone |
boolean |
true |
Plan B standalone. |
standaloneContainer |
string |
'#root' |
Selector usado en modo standalone. |
onMount / onUnmount |
function |
null |
Callbacks de ciclo de vida. |
wuAngular.registerStandalone('dashboard', AppComponent, { createApplication, createComponent, provideZoneChangeDetection, appConfig: { providers: [provideHttpClient(), provideRouter(routes)], },});register(appName, AppModule, options)
Sección titulada «register(appName, AppModule, options)»La vía NgModule. Arranca con platformBrowserDynamic().bootstrapModule().
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';import { wuAngular } from 'wu-framework/adapters/angular';import { AppModule } from './app/app.module';
wuAngular.register('legacy-admin', AppModule, { platformFactory: platformBrowserDynamic, rootSelector: 'app-root', providers: [],});| Opción | Tipo | Por defecto | Notas |
|---|---|---|---|
platformFactory |
function |
null |
platformBrowserDynamic. Pásalo para evitar problemas de resolución del bundler. |
providers |
Array |
[] |
Providers extra de arranque, entregados a platformFactory(providers). |
rootSelector |
string |
'app-root' |
Etiqueta creada dentro del contenedor para alojar la app. También recibe data-wu-angular-root="<appName>". |
standalone |
boolean |
true |
Plan B standalone. |
standaloneContainer |
string |
'#root' |
Selector usado en modo standalone. |
onMount / onUnmount |
function |
null |
Reciben (container, moduleRef). |
registerElement(appName, Component, options)
Sección titulada «registerElement(appName, Component, options)»Envuelve un componente standalone como custom element mediante
@angular/elements (que debe estar instalado) y luego deja que Wu coloque la
etiqueta.
wuAngular.registerElement('mfe-angular', AppComponent, { elementTag: 'mfe-angular-content',});| Opción | Tipo | Por defecto |
|---|---|---|
elementTag |
string |
`${appName}-element` |
appConfig |
ApplicationConfig |
{} |
standalone |
boolean |
true |
standaloneContainer |
string |
'#root' |
onMount / onUnmount |
function |
null |
El elemento se define una sola vez (primero se comprueba customElements.get) y
se reutiliza entre montajes.
Sin props vivas, sin hidratación
Sección titulada «Sin props vivas, sin hidratación»await wu.update('dashboard', { theme: 'dark' }); // no hace nadaNinguno de los tres puntos de entrada de Angular anuncia update ni hydrate.
Para meter datos en una micro-app Angular en ejecución, usa el store o el bus de
eventos, que es justo para lo que sirve createWuService().
createWuService()
Sección titulada «createWuService()»Una factoría simple (no un @Injectable de Angular) que agrupa el bus de
eventos y el store con seguimiento de suscripciones:
import { Component, OnInit, OnDestroy } from '@angular/core';import { createWuService } from 'wu-framework/adapters/angular';
@Component({ selector: 'app-root', standalone: true, template: '…' })export class AppComponent implements OnInit, OnDestroy { private wu = createWuService(); orders: Order[] = []; theme = 'light';
ngOnInit() { this.wu.on('order:new', (e) => this.orders.push(e.data)); this.wu.onStateChange('theme.mode', (e) => (this.theme = e.value)); const user = this.wu.getState('user'); }
save(name: string) { this.wu.setState('store.name', name); this.wu.emit('settings:saved', { name }); }
ngOnDestroy() { this.wu.destroy(); // elimina cada listener de on() / onStateChange() }}Devuelve { emit, on, once, off, getState, setState, onStateChange, destroy, wu }.
Lado del shell: createWuSlotComponent()
Sección titulada «Lado del shell: createWuSlotComponent()»Los componentes de Angular no se pueden crear de forma genérica en tiempo de ejecución, así que el adapter devuelve un objeto de configuración que ensamblas en un componente real en tu propio código:
import { Component, Input, Output, EventEmitter, ElementRef, ViewChild } from '@angular/core';import { createWuSlotComponent } from 'wu-framework/adapters/angular';
const config = createWuSlotComponent();
@Component({ selector: 'wu-slot', template: config.template, styles: config.styles,})export class WuSlotComponent { @Input() name!: string; @Input() url!: string; @Input() fallbackText?: string; @Output() load = new EventEmitter(); // La salida se llama 'error' para el padre, pero la propiedad DEBE llamarse // errorEvent: `error` guarda el mensaje que renderiza el template, así que no // puede ser también el EventEmitter. @Output('error') errorEvent = new EventEmitter(); error: string | null = null; loading = true;
@ViewChild('container') container!: ElementRef;
// Implementa los métodos de ciclo de vida de config.methods}config provee { selector, template, styles, methods }. El template ya maneja
los estados de carga y error y estampa data-wu-app / data-wu-url.
getWuSlotModuleConfig() devuelve el cableado del NgModule para shells que
quieran declarar y exportar WuSlotComponent:
// { imports: ['CommonModule'], declarations: ['WuSlotComponent'], exports: ['WuSlotComponent'] }IA: createWuAIService()
Sección titulada «IA: createWuAIService()»import { createWuAIService } from 'wu-framework/adapters/angular';
@Component({ /* … */ })export class AssistantComponent { private ai = createWuAIService();
async ask(text: string) { await this.ai.send(text); }}Misma forma que los helpers de IA sin streaming de los otros adapters: envuelve
wu.ai.send() con contabilidad local de mensajes. Consulta
Visión general de IA.
Configuración de Vite sin AnalogJS
Sección titulada «Configuración de Vite sin AnalogJS»import { defineConfig } from 'vite';
export default defineConfig({ server: { port: 5008, cors: true }, esbuild: { target: 'es2022' },});// tsconfig.json — decoradores para esbuild{ "compilerOptions": { "experimentalDecorators": true, "useDefineForClassFields": false }}Importa @angular/compiler en main.ts para ejecutar en modo JIT. cors: true
es obligatorio para que el shell pueda pedir wu.json y el bundle de entrada
desde otro origen.
Exports
Sección titulada «Exports»import { wuAngular, // export por defecto register, registerStandalone, registerElement, createWuService, createWuSlotComponent, getWuSlotModuleConfig, createWuAIService, getWuInstance, waitForWu,} from 'wu-framework/adapters/angular';Desde el barrel, estos pasan a ser registerAngular y
registerAngularStandalone.
