wu-framework 1.1.18 → 1.1.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -25,7 +25,7 @@
25
25
 
26
26
  ---
27
27
 
28
- Run **React, Vue, Angular, Svelte, Solid, Preact, Lit, and Vanilla JS** micro-apps side by side in the same page. Each app lives in its own Shadow DOM with full CSS isolation. Apps communicate through a shared event bus and store — no tight coupling, no iframes.
28
+ Run **React, Vue, Angular, Svelte, Solid, Preact, Lit, Qwik, Alpine.js, Stencil, HTMX, Stimulus, and Vanilla JS** micro-apps side by side in the same page. Each app lives in its own Shadow DOM with full CSS isolation. Apps communicate through a shared event bus and store — no tight coupling, no iframes.
29
29
 
30
30
  Add AI to any app with one line. Connect your own LLM (OpenAI, Anthropic, Ollama) and your app gains context-aware tool calling, autonomous agents, and cross-app orchestration. **WebMCP ready** for Chrome 146+.
31
31
 
@@ -68,7 +68,7 @@ await wu.ai.send('Add product SKU-42 to the cart');
68
68
 
69
69
  | | **Wu Framework** | **single-spa** | **Module Federation** | **iframes** |
70
70
  |---|:---:|:---:|:---:|:---:|
71
- | Framework adapters | **8** | 4 | 1* | Any |
71
+ | Framework adapters | **13** | 4 | 1* | Any |
72
72
  | Shadow DOM isolation | Yes | No | No | Yes (heavy) |
73
73
  | Shared event bus | Built-in | Manual | Manual | postMessage |
74
74
  | Shared store | Built-in | Manual | Manual | No |
@@ -87,7 +87,7 @@ await wu.ai.send('Add product SKU-42 to the cart');
87
87
 
88
88
  ### Core
89
89
 
90
- - **8 Framework Adapters** — React, Vue, Angular, Svelte, Solid, Preact, Lit, Vanilla
90
+ - **13 Framework Adapters** — React, Vue, Angular, Svelte, Solid, Preact, Lit, Qwik, Alpine.js, Stencil, HTMX, Stimulus, Vanilla
91
91
  - **Shadow DOM Isolation** — CSS and DOM fully sandboxed per app
92
92
  - **3 Sandbox Strategies** — Shadow DOM, Proxy, iframe — choose per app
93
93
  - **3 CSS Isolation Modes** — `shared`, `isolated`, `fully-isolated` per app
@@ -138,6 +138,26 @@ wuAngular.registerStandalone('settings', AppComponent, { createApplication, crea
138
138
  import { wuSvelte } from 'wu-framework/adapters/svelte';
139
139
  wuSvelte.registerSvelte5('dashboard', App);
140
140
 
141
+ // Qwik
142
+ import { wuQwik } from 'wu-framework/adapters/qwik';
143
+ wuQwik.register('widget', QwikApp);
144
+
145
+ // Alpine.js
146
+ import { wuAlpine } from 'wu-framework/adapters/alpine';
147
+ wuAlpine.register('search', initFn);
148
+
149
+ // Stencil (Web Components)
150
+ import { wuStencil } from 'wu-framework/adapters/stencil';
151
+ wuStencil.register('badge', 'my-badge');
152
+
153
+ // HTMX
154
+ import { wuHtmx } from 'wu-framework/adapters/htmx';
155
+ wuHtmx.register('feed', { template: '<div hx-get="/api/feed">...</div>' });
156
+
157
+ // Stimulus
158
+ import { wuStimulus } from 'wu-framework/adapters/stimulus';
159
+ wuStimulus.register('form', { controllers: { hello: HelloController }, template: '...' });
160
+
141
161
  // Same pattern for Solid, Preact, Lit, Vanilla
142
162
  ```
143
163
 
@@ -324,7 +344,7 @@ QA sets a cookie → only **their browser** sees the override. Everyone else see
324
344
  | Source files | 79 |
325
345
  | Lines of code | 23,442 |
326
346
  | Test cases | **650** |
327
- | Framework adapters | 8 |
347
+ | Framework adapters | 13 |
328
348
  | AI modules | 12 |
329
349
  | Core modules | 23 |
330
350
  | Runtime dependencies | **0** |
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "wu-framework",
3
- "version": "1.1.18",
4
- "description": "Universal Microfrontends Framework - 8 frameworks, zero config, Shadow DOM isolation",
3
+ "version": "1.1.19",
4
+ "description": "Universal Microfrontends Framework - 13 frameworks, zero config, Shadow DOM isolation",
5
5
  "main": "dist/wu-framework.cjs.js",
6
6
  "module": "src/index.js",
7
7
  "browser": "dist/wu-framework.umd.js",
@@ -149,18 +149,21 @@
149
149
  },
150
150
  "peerDependencies": {
151
151
  "@angular/core": ">=14.0.0",
152
+ "@builder.io/qwik": ">=1.0.0",
153
+ "@hotwired/stimulus": ">=3.0.0",
154
+ "@stencil/core": ">=4.0.0",
155
+ "alpinejs": ">=3.0.0",
156
+ "htmx.org": ">=2.0.0",
152
157
  "lit": ">=2.0.0",
153
158
  "preact": ">=10.0.0",
154
159
  "react": ">=16.8.0",
155
160
  "react-dom": ">=16.8.0",
156
161
  "solid-js": ">=1.0.0",
157
162
  "svelte": ">=3.0.0",
158
- "vue": ">=3.0.0",
159
- "alpinejs": ">=3.0.0",
160
- "@builder.io/qwik": ">=1.0.0",
161
- "@stencil/core": ">=4.0.0",
162
- "htmx.org": ">=2.0.0",
163
- "@hotwired/stimulus": ">=3.0.0"
163
+ "vue": ">=3.0.0"
164
+ },
165
+ "overrides": {
166
+ "serialize-javascript": "^7.0.3"
164
167
  },
165
168
  "peerDependenciesMeta": {
166
169
  "react": {
@@ -1,214 +1,50 @@
1
1
  /**
2
2
  * WU-FRAMEWORK QWIK ADAPTER
3
3
  *
4
- * Integrates Qwik components into Wu Framework's microfrontend
5
- * orchestration. Qwik's resumability model -- where the framework
6
- * serializes state into HTML and lazily hydrates on interaction --
7
- * makes it a natural fit for microfrontend boundaries. The adapter
8
- * leverages dynamic import of @builder.io/qwik to keep the shell
9
- * bundle zero-cost until a Qwik island actually mounts.
4
+ * Integrates Qwik components (component$) into Wu Framework's
5
+ * microfrontend orchestration via @builder.io/qwik render API.
10
6
  *
11
- * @example
12
- * import { wuQwik } from 'wu-framework/adapters/qwik';
13
- * import { App } from './App';
14
- *
15
- * wuQwik.register('my-qwik-app', App);
16
- *
17
- * @example
18
- * // With props and lifecycle hooks
19
- * wuQwik.register('dashboard', DashboardComponent, {
20
- * props: { userId: 42 },
21
- * onMount: (container) => console.log('Qwik island mounted'),
22
- * onUnmount: (container) => console.log('Qwik island destroyed')
23
- * });
24
- */
25
-
26
- // Adapter-scoped state
27
- const adapterState = {
28
- apps: new Map()
29
- };
30
-
31
- /**
32
- * Obtiene la instancia de Wu Framework
33
- */
34
- function getWuInstance() {
35
- if (typeof window === 'undefined') return null;
36
-
37
- return window.wu
38
- || window.parent?.wu
39
- || window.top?.wu
40
- || null;
41
- }
42
-
43
- /**
44
- * Espera a que Wu Framework este disponible
45
- */
46
- function waitForWu(timeout = 5000) {
47
- return new Promise((resolve, reject) => {
48
- const wu = getWuInstance();
49
- if (wu) {
50
- resolve(wu);
51
- return;
52
- }
53
-
54
- const startTime = Date.now();
55
-
56
- const handleWuReady = () => {
57
- cleanup();
58
- resolve(getWuInstance());
59
- };
60
-
61
- window.addEventListener('wu:ready', handleWuReady);
62
- window.addEventListener('wu:app:ready', handleWuReady);
63
-
64
- const checkInterval = setInterval(() => {
65
- const wu = getWuInstance();
66
- if (wu) {
67
- cleanup();
68
- resolve(wu);
69
- return;
70
- }
71
-
72
- if (Date.now() - startTime > timeout) {
73
- cleanup();
74
- reject(new Error(`Wu Framework not found after ${timeout}ms`));
75
- }
76
- }, 200);
77
-
78
- function cleanup() {
79
- clearInterval(checkInterval);
80
- window.removeEventListener('wu:ready', handleWuReady);
81
- window.removeEventListener('wu:app:ready', handleWuReady);
82
- }
83
- });
84
- }
85
-
86
- /**
87
- * Registra un componente Qwik como microfrontend
88
- *
89
- * @param {string} appName - Nombre unico del microfrontend
90
- * @param {Function} Component - Componente Qwik (creado con component$)
91
- * @param {Object} [options] - Opciones adicionales
92
- * @param {Object} [options.props={}] - Props a pasar al componente
93
- * @param {Function} [options.onMount] - Callback despues de montar
94
- * @param {Function} [options.onUnmount] - Callback antes de desmontar
95
- * @param {boolean} [options.standalone=true] - Permitir ejecucion standalone
96
- * @param {string} [options.standaloneContainer='#app'] - Selector para modo standalone
97
- * @returns {Promise<boolean>} true si el registro fue exitoso
7
+ * Qwik uses QRL-based event delegation — onClick$, onInput$, etc.
8
+ * are NOT regular DOM listeners. The qwikloader script must be
9
+ * active in the document to intercept events and dispatch QRLs.
98
10
  */
99
- async function register(appName, Component, options = {}) {
100
- const {
101
- props = {},
102
- onMount = null,
103
- onUnmount = null,
104
- standalone = true,
105
- standaloneContainer = '#app'
106
- } = options;
107
11
 
108
- if (!Component) {
109
- throw new Error(`[WuQwik] Component is required for ${appName}`);
110
- }
111
-
112
- // Mount function
113
- const mountApp = (container) => {
114
- if (!container) {
115
- console.error(`[WuQwik] Mount failed for ${appName}: container is null`);
116
- return;
117
- }
118
-
119
- // Prevent double-mount
120
- if (adapterState.apps.has(appName)) {
121
- console.warn(`[WuQwik] ${appName} already mounted, unmounting first`);
122
- unmountApp();
123
- }
124
-
125
- try {
126
- container.innerHTML = '';
127
-
128
- // Dynamic import keeps Qwik out of the critical path
129
- import('@builder.io/qwik').then(({ render, jsx }) => {
130
- render(container, jsx(Component, props));
131
-
132
- adapterState.apps.set(appName, {
133
- container,
134
- Component,
135
- props
136
- });
137
-
138
- console.log(`[WuQwik] ${appName} mounted successfully`);
139
-
140
- if (onMount) {
141
- onMount(container);
142
- }
143
- }).catch((err) => {
144
- console.error(`[WuQwik] Failed to import @builder.io/qwik for ${appName}:`, err);
145
- container.innerHTML = `<div style="color:#721c24;padding:1rem;">Failed to load Qwik runtime</div>`;
146
- });
147
- } catch (error) {
148
- console.error(`[WuQwik] Mount error for ${appName}:`, error);
149
- throw error;
150
- }
151
- };
12
+ export const wuQwik = {
13
+ async register(appName, Component, options = {}) {
14
+ const wu = window.wu || window.parent?.wu;
15
+ if (!wu) return;
152
16
 
153
- // Unmount function
154
- const unmountApp = (container) => {
155
- const appData = adapterState.apps.get(appName);
17
+ const qwik = await import('@builder.io/qwik');
156
18
 
157
- if (appData) {
19
+ // Inject qwikloader once per document (event delegation for QRLs)
20
+ if (!('__q_context__' in document)) {
158
21
  try {
159
- if (onUnmount) {
160
- onUnmount(appData.container);
161
- }
162
-
163
- appData.container.innerHTML = '';
164
- adapterState.apps.delete(appName);
165
-
166
- console.log(`[WuQwik] ${appName} unmounted successfully`);
167
- } catch (error) {
168
- console.error(`[WuQwik] Unmount error for ${appName}:`, error);
22
+ const { QWIK_LOADER } = await import('@builder.io/qwik/loader');
23
+ const s = document.createElement('script');
24
+ s.textContent = QWIK_LOADER;
25
+ document.head.appendChild(s);
26
+ } catch (e) {
27
+ console.warn('[WuQwik] qwikloader not available:', e.message);
169
28
  }
170
29
  }
171
30
 
172
- if (container) {
173
- container.innerHTML = '';
174
- }
175
- };
176
-
177
- // Register with Wu Framework or fall back to standalone
178
- try {
179
- const wu = await waitForWu(3000);
180
-
181
31
  wu.define(appName, {
182
- mount: mountApp,
183
- unmount: unmountApp
184
- });
185
-
186
- console.log(`[WuQwik] ${appName} registered with Wu Framework`);
187
- return true;
188
-
189
- } catch (error) {
190
- console.warn(`[WuQwik] Wu Framework not available for ${appName}`);
191
-
192
- if (standalone) {
193
- const containerElement = document.querySelector(standaloneContainer);
194
-
195
- if (containerElement) {
196
- console.log(`[WuQwik] Running ${appName} in standalone mode`);
197
- mountApp(containerElement);
198
- return true;
32
+ async mount(container) {
33
+ container.innerHTML = '';
34
+ try {
35
+ const vnode = qwik.jsx(Component, options.props || {});
36
+ await qwik.render(container, vnode);
37
+ } catch (e) {
38
+ console.error('[WuQwik] render error:', e);
39
+ container.innerHTML = '<pre style="color:#f66;padding:1rem">' + e.message + '</pre>';
40
+ }
41
+ },
42
+ unmount(container) {
43
+ container.innerHTML = '';
199
44
  }
200
- }
201
-
202
- return false;
45
+ });
203
46
  }
204
- }
205
-
206
- // Public API
207
- export const wuQwik = {
208
- register,
209
- getWuInstance,
210
- waitForWu
211
47
  };
212
48
 
213
- export { register, getWuInstance, waitForWu };
49
+ export const { register } = wuQwik;
214
50
  export default wuQwik;