@hai3/react 0.3.0-alpha.0 → 0.4.0-alpha.0
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/CLAUDE.md +255 -43
- package/commands/hai3-new-mfe.md +167 -0
- package/dist/index.cjs +539 -280
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +342 -90
- package/dist/index.d.ts +342 -90
- package/dist/index.js +422 -149
- package/dist/index.js.map +1 -1
- package/dist/types-CcLYaLwF.d.cts +136 -0
- package/dist/types-CcLYaLwF.d.ts +136 -0
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +3 -238
- package/dist/types.d.ts +3 -238
- package/llms.txt +72 -9
- package/package.json +10 -3
package/CLAUDE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @hai3/react
|
|
2
2
|
|
|
3
|
-
React bindings and hooks for HAI3 applications. Provides the React integration layer.
|
|
3
|
+
React bindings and hooks for HAI3 applications. Provides the React integration layer with MFE (Microfrontend) support.
|
|
4
4
|
|
|
5
5
|
## React Layer
|
|
6
6
|
|
|
@@ -46,7 +46,13 @@ import { useHAI3 } from '@hai3/react';
|
|
|
46
46
|
|
|
47
47
|
function MyComponent() {
|
|
48
48
|
const app = useHAI3();
|
|
49
|
-
|
|
49
|
+
|
|
50
|
+
// Access MFE-enabled registry
|
|
51
|
+
const extensions = app.screensetsRegistry.getRegisteredExtensions();
|
|
52
|
+
|
|
53
|
+
// Access MFE actions
|
|
54
|
+
await app.actions.loadExtension({ extensionId: 'home' });
|
|
55
|
+
await app.actions.mountExtension({ extensionId: 'home', domainId: 'screen', container });
|
|
50
56
|
}
|
|
51
57
|
```
|
|
52
58
|
|
|
@@ -56,11 +62,10 @@ Type-safe Redux hooks:
|
|
|
56
62
|
|
|
57
63
|
```tsx
|
|
58
64
|
import { useAppDispatch, useAppSelector } from '@hai3/react';
|
|
59
|
-
import { selectActiveScreen } from '@hai3/react';
|
|
60
65
|
|
|
61
66
|
function MyComponent() {
|
|
62
67
|
const dispatch = useAppDispatch();
|
|
63
|
-
const activeScreen = useAppSelector(
|
|
68
|
+
const activeScreen = useAppSelector((state) => state.layout.screen.activeScreen);
|
|
64
69
|
}
|
|
65
70
|
```
|
|
66
71
|
|
|
@@ -105,83 +110,213 @@ function HomeScreen() {
|
|
|
105
110
|
}
|
|
106
111
|
```
|
|
107
112
|
|
|
108
|
-
####
|
|
113
|
+
#### useTheme
|
|
109
114
|
|
|
110
|
-
|
|
115
|
+
Access theme utilities:
|
|
111
116
|
|
|
112
117
|
```tsx
|
|
113
|
-
import {
|
|
118
|
+
import { useTheme } from '@hai3/react';
|
|
114
119
|
|
|
115
|
-
function
|
|
116
|
-
const {
|
|
120
|
+
function ThemeToggle() {
|
|
121
|
+
const { currentTheme, themes, setTheme } = useTheme();
|
|
117
122
|
|
|
118
123
|
return (
|
|
119
|
-
<
|
|
120
|
-
|
|
121
|
-
|
|
124
|
+
<select value={currentTheme} onChange={(e) => setTheme(e.target.value)}>
|
|
125
|
+
{themes.map((theme) => (
|
|
126
|
+
<option key={theme.id} value={theme.id}>{theme.name}</option>
|
|
127
|
+
))}
|
|
128
|
+
</select>
|
|
122
129
|
);
|
|
123
130
|
}
|
|
124
131
|
```
|
|
125
132
|
|
|
126
|
-
|
|
133
|
+
### MFE Hooks
|
|
127
134
|
|
|
128
|
-
|
|
135
|
+
#### useMfeBridge
|
|
136
|
+
|
|
137
|
+
Access the MFE bridge for child MFEs:
|
|
129
138
|
|
|
130
139
|
```tsx
|
|
131
|
-
import {
|
|
140
|
+
import { useMfeBridge } from '@hai3/react';
|
|
141
|
+
import { HAI3_ACTION_LOAD_EXT, HAI3_SHARED_PROPERTY_THEME } from '@hai3/react';
|
|
132
142
|
|
|
133
|
-
function
|
|
134
|
-
const
|
|
143
|
+
function MyExtension() {
|
|
144
|
+
const bridge = useMfeBridge();
|
|
145
|
+
|
|
146
|
+
// Execute actions chain on parent
|
|
147
|
+
await bridge.executeActionsChain({
|
|
148
|
+
action: { type: HAI3_ACTION_LOAD_EXT, target: 'screen', payload: { extensionId: 'other' } }
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Get shared property
|
|
152
|
+
const theme = bridge.getProperty(HAI3_SHARED_PROPERTY_THEME);
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
#### useSharedProperty
|
|
157
|
+
|
|
158
|
+
Subscribe to shared property changes:
|
|
159
|
+
|
|
160
|
+
```tsx
|
|
161
|
+
import { useSharedProperty, HAI3_SHARED_PROPERTY_THEME } from '@hai3/react';
|
|
162
|
+
|
|
163
|
+
function ThemedComponent() {
|
|
164
|
+
const theme = useSharedProperty(HAI3_SHARED_PROPERTY_THEME);
|
|
165
|
+
|
|
166
|
+
return <div style={{ backgroundColor: theme?.primaryColor }}>...</div>;
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
#### useHostAction
|
|
171
|
+
|
|
172
|
+
Invoke actions on the host application:
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
import { useHostAction, HAI3_ACTION_LOAD_EXT } from '@hai3/react';
|
|
176
|
+
|
|
177
|
+
function MyExtension() {
|
|
178
|
+
const loadExtension = useHostAction(HAI3_ACTION_LOAD_EXT);
|
|
179
|
+
|
|
180
|
+
const handleClick = () => {
|
|
181
|
+
loadExtension({ extensionId: 'other' });
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
return <button onClick={handleClick}>Load Extension</button>;
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
#### useDomainExtensions
|
|
189
|
+
|
|
190
|
+
Subscribe to extensions in a domain:
|
|
191
|
+
|
|
192
|
+
```tsx
|
|
193
|
+
import { useDomainExtensions } from '@hai3/react';
|
|
194
|
+
|
|
195
|
+
function ScreenList() {
|
|
196
|
+
const screenExtensions = useDomainExtensions('screen');
|
|
135
197
|
|
|
136
198
|
return (
|
|
137
|
-
<
|
|
138
|
-
{
|
|
139
|
-
<
|
|
199
|
+
<ul>
|
|
200
|
+
{screenExtensions.map((ext) => (
|
|
201
|
+
<li key={ext.id}>{ext.title}</li>
|
|
140
202
|
))}
|
|
141
|
-
</
|
|
203
|
+
</ul>
|
|
142
204
|
);
|
|
143
205
|
}
|
|
144
206
|
```
|
|
145
207
|
|
|
146
|
-
|
|
208
|
+
#### useRegisteredPackages
|
|
209
|
+
|
|
210
|
+
Subscribe to registered GTS packages:
|
|
211
|
+
|
|
212
|
+
```tsx
|
|
213
|
+
import { useRegisteredPackages } from '@hai3/react';
|
|
214
|
+
|
|
215
|
+
function PackageList() {
|
|
216
|
+
const packages = useRegisteredPackages();
|
|
217
|
+
|
|
218
|
+
return (
|
|
219
|
+
<ul>
|
|
220
|
+
{packages.map((pkg) => (
|
|
221
|
+
<li key={pkg}>{pkg}</li>
|
|
222
|
+
))}
|
|
223
|
+
</ul>
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
```
|
|
147
227
|
|
|
148
|
-
####
|
|
228
|
+
#### useActivePackage
|
|
149
229
|
|
|
150
|
-
|
|
230
|
+
Subscribe to the active GTS package (the package of the currently mounted screen extension):
|
|
151
231
|
|
|
152
232
|
```tsx
|
|
153
|
-
import {
|
|
233
|
+
import { useActivePackage } from '@hai3/react';
|
|
154
234
|
|
|
155
|
-
function
|
|
235
|
+
function ActivePackageIndicator() {
|
|
236
|
+
const activePackage = useActivePackage();
|
|
237
|
+
|
|
238
|
+
if (!activePackage) {
|
|
239
|
+
return <div>No active screen</div>;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return <div>Active: {activePackage}</div>;
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### MFE Components
|
|
247
|
+
|
|
248
|
+
#### MfeProvider
|
|
249
|
+
|
|
250
|
+
Provide MFE context for child extensions:
|
|
251
|
+
|
|
252
|
+
```tsx
|
|
253
|
+
import { MfeProvider } from '@hai3/react';
|
|
254
|
+
|
|
255
|
+
function MfeHost() {
|
|
156
256
|
return (
|
|
157
|
-
<
|
|
158
|
-
<
|
|
159
|
-
|
|
160
|
-
fallback={<Loading />}
|
|
161
|
-
errorFallback={(error) => <Error error={error} />}
|
|
162
|
-
/>
|
|
163
|
-
</Layout>
|
|
164
|
-
</HAI3Provider>
|
|
257
|
+
<MfeProvider bridge={parentBridge}>
|
|
258
|
+
<ExtensionContainer />
|
|
259
|
+
</MfeProvider>
|
|
165
260
|
);
|
|
166
261
|
}
|
|
167
262
|
```
|
|
168
263
|
|
|
264
|
+
#### ExtensionDomainSlot
|
|
265
|
+
|
|
266
|
+
Render extensions into a domain slot:
|
|
267
|
+
|
|
268
|
+
```tsx
|
|
269
|
+
import { ExtensionDomainSlot } from '@hai3/react';
|
|
270
|
+
|
|
271
|
+
function LayoutScreen() {
|
|
272
|
+
return (
|
|
273
|
+
<div>
|
|
274
|
+
<ExtensionDomainSlot
|
|
275
|
+
domainId="screen"
|
|
276
|
+
containerRef={screenContainerRef}
|
|
277
|
+
fallback={<Loading />}
|
|
278
|
+
/>
|
|
279
|
+
</div>
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
#### RefContainerProvider
|
|
285
|
+
|
|
286
|
+
Provide container references for MFE mounting:
|
|
287
|
+
|
|
288
|
+
```tsx
|
|
289
|
+
import { RefContainerProvider } from '@hai3/react';
|
|
290
|
+
|
|
291
|
+
function Layout() {
|
|
292
|
+
return (
|
|
293
|
+
<RefContainerProvider>
|
|
294
|
+
<ScreenContainer />
|
|
295
|
+
<SidebarContainer />
|
|
296
|
+
</RefContainerProvider>
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Components
|
|
302
|
+
|
|
169
303
|
## Key Rules
|
|
170
304
|
|
|
171
305
|
1. **Wrap with HAI3Provider** - Required for all hooks to work
|
|
172
|
-
2. **Use hooks for state access** - Don't import selectors directly from @hai3/
|
|
306
|
+
2. **Use hooks for state access** - Don't import selectors directly from @hai3/framework
|
|
173
307
|
3. **Lazy load translations** - Use `useScreenTranslations` for screen-level i18n
|
|
174
|
-
4. **
|
|
308
|
+
4. **Use MFE hooks for extensions** - `useMfeBridge`, `useSharedProperty`, `useHostAction`, `useDomainExtensions`
|
|
309
|
+
5. **NO Layout components here** - Layout and UI components belong in L4 (user's project via CLI scaffolding)
|
|
175
310
|
|
|
176
311
|
## Re-exports
|
|
177
312
|
|
|
178
313
|
For convenience, this package re-exports everything from @hai3/framework:
|
|
179
314
|
|
|
180
315
|
- All SDK primitives (eventBus, createStore, etc.)
|
|
181
|
-
- All plugins (screensets, themes, layout, etc.)
|
|
316
|
+
- All plugins (screensets, themes, layout, microfrontends, etc.)
|
|
182
317
|
- All registries and factory functions
|
|
183
|
-
- All
|
|
184
|
-
- All
|
|
318
|
+
- All types (including MFE types)
|
|
319
|
+
- All MFE actions, selectors, and domain constants
|
|
185
320
|
|
|
186
321
|
This allows users to import everything from `@hai3/react` without needing `@hai3/framework` directly.
|
|
187
322
|
|
|
@@ -189,7 +324,9 @@ This allows users to import everything from `@hai3/react` without needing `@hai3
|
|
|
189
324
|
|
|
190
325
|
### Components
|
|
191
326
|
- `HAI3Provider` - Main context provider
|
|
192
|
-
- `
|
|
327
|
+
- `MfeProvider` - MFE context provider
|
|
328
|
+
- `ExtensionDomainSlot` - Domain slot renderer
|
|
329
|
+
- `RefContainerProvider` - Container reference provider
|
|
193
330
|
|
|
194
331
|
### Hooks
|
|
195
332
|
- `useHAI3` - Access app instance
|
|
@@ -197,13 +334,88 @@ This allows users to import everything from `@hai3/react` without needing `@hai3
|
|
|
197
334
|
- `useAppSelector` - Typed selector
|
|
198
335
|
- `useTranslation` - Translation utilities
|
|
199
336
|
- `useScreenTranslations` - Screen translation loading
|
|
200
|
-
- `useNavigation` - Navigation utilities
|
|
201
337
|
- `useTheme` - Theme utilities
|
|
338
|
+
- `useMfeBridge` - Access MFE bridge
|
|
339
|
+
- `useSharedProperty` - Subscribe to shared property
|
|
340
|
+
- `useHostAction` - Invoke host action
|
|
341
|
+
- `useDomainExtensions` - Subscribe to domain extensions
|
|
342
|
+
- `useRegisteredPackages` - Subscribe to registered GTS packages
|
|
343
|
+
- `useActivePackage` - Subscribe to active GTS package
|
|
202
344
|
|
|
203
345
|
### Context
|
|
204
346
|
- `HAI3Context` - React context (for advanced use)
|
|
347
|
+
- `MfeContext` - MFE context (for advanced use)
|
|
205
348
|
|
|
206
349
|
### Types
|
|
207
|
-
- `HAI3ProviderProps
|
|
208
|
-
- `
|
|
350
|
+
- `HAI3ProviderProps`
|
|
351
|
+
- `MfeProviderProps`, `ExtensionDomainSlotProps`
|
|
352
|
+
- `UseTranslationReturn`, `UseThemeReturn`
|
|
209
353
|
- All types from @hai3/framework
|
|
354
|
+
|
|
355
|
+
## Migration from Legacy API
|
|
356
|
+
|
|
357
|
+
The `useNavigation` hook has been removed. Use MFE hooks and actions instead:
|
|
358
|
+
|
|
359
|
+
### Removed Hook
|
|
360
|
+
- `useNavigation()` (replaced by MFE actions and hooks)
|
|
361
|
+
|
|
362
|
+
### Migration Examples
|
|
363
|
+
|
|
364
|
+
**OLD**: Navigate using hook
|
|
365
|
+
```tsx
|
|
366
|
+
import { useNavigation } from '@hai3/react';
|
|
367
|
+
|
|
368
|
+
function MyComponent() {
|
|
369
|
+
const { navigateToScreen } = useNavigation();
|
|
370
|
+
|
|
371
|
+
return (
|
|
372
|
+
<button onClick={() => navigateToScreen('demo', 'home')}>
|
|
373
|
+
Go Home
|
|
374
|
+
</button>
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
**NEW**: Mount extension using app actions
|
|
380
|
+
```tsx
|
|
381
|
+
import { useHAI3 } from '@hai3/react';
|
|
382
|
+
|
|
383
|
+
function MyComponent() {
|
|
384
|
+
const app = useHAI3();
|
|
385
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
386
|
+
|
|
387
|
+
const handleNavigate = async () => {
|
|
388
|
+
if (containerRef.current) {
|
|
389
|
+
await app.actions.mountExtension({
|
|
390
|
+
extensionId: 'home',
|
|
391
|
+
domainId: 'screen',
|
|
392
|
+
container: containerRef.current,
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
return (
|
|
398
|
+
<>
|
|
399
|
+
<button onClick={handleNavigate}>Go Home</button>
|
|
400
|
+
<div ref={containerRef} />
|
|
401
|
+
</>
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
**NEW (Alternative)**: Use ExtensionDomainSlot
|
|
407
|
+
```tsx
|
|
408
|
+
import { ExtensionDomainSlot } from '@hai3/react';
|
|
409
|
+
|
|
410
|
+
function MyComponent() {
|
|
411
|
+
return (
|
|
412
|
+
<ExtensionDomainSlot
|
|
413
|
+
domainId="screen"
|
|
414
|
+
containerRef={screenContainerRef}
|
|
415
|
+
fallback={<Loading />}
|
|
416
|
+
/>
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
See the MFE migration guide in the project documentation for detailed migration steps.
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
<!-- @standalone -->
|
|
2
|
+
# hai3:new-mfe - Create New Microfrontend Package
|
|
3
|
+
|
|
4
|
+
## PREREQUISITES (CRITICAL - STOP IF FAILED)
|
|
5
|
+
|
|
6
|
+
1. MFE must be associated with a screenset
|
|
7
|
+
2. Screenset must exist (run `hai3-new-screenset` first if needed)
|
|
8
|
+
3. Vite and Module Federation must be configured
|
|
9
|
+
|
|
10
|
+
## QUICK START
|
|
11
|
+
|
|
12
|
+
For a screenset named `{screensetName}` with a new MFE:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# 1. Create the MFE package in src/mfe_packages/{screensetName}-mfe/
|
|
16
|
+
cp -r packages/cli/template-sources/mfe-package/ src/mfe_packages/{screensetName}-mfe/
|
|
17
|
+
|
|
18
|
+
# 2. Update variables in package.json and vite.config.ts:
|
|
19
|
+
# - Replace {{mfeName}} with your screenset name (camelCase)
|
|
20
|
+
# - Replace {{port}} with available port (3001, 3010, 3020, etc)
|
|
21
|
+
# - IMPORTANT: set preview script to "vite preview --port {{port}}"
|
|
22
|
+
|
|
23
|
+
# 3. Install dependencies
|
|
24
|
+
cd src/mfe_packages/{screensetName}-mfe
|
|
25
|
+
npm install
|
|
26
|
+
|
|
27
|
+
# 4. Create src/lifecycle.tsx that extends ThemeAwareReactLifecycle
|
|
28
|
+
|
|
29
|
+
# 5. Regenerate MFE manifests so bootstrap.ts picks up the new package
|
|
30
|
+
npm run generate:mfe-manifests
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## CONFIGURATION REQUIREMENTS
|
|
34
|
+
|
|
35
|
+
✅ **Correct preview script** (required for port auto-discovery):
|
|
36
|
+
```json
|
|
37
|
+
"preview": "vite preview --port {{port}}"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
✅ **Correct dev script** (for hot reload):
|
|
41
|
+
```json
|
|
42
|
+
"dev": "vite --port {{port}}"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
❌ **WRONG** (don't use this for dev):
|
|
46
|
+
```json
|
|
47
|
+
"dev": "vite build && vite preview --port {{port}}"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## PORT ALLOCATION
|
|
51
|
+
|
|
52
|
+
Reserve ports for MFE packages:
|
|
53
|
+
- **3001**: demo-mfe
|
|
54
|
+
- **3010+**: (next available: 3010, 3020, 3030, ...)
|
|
55
|
+
- **5173**: Main app
|
|
56
|
+
|
|
57
|
+
## LIFECYCLE TEMPLATE
|
|
58
|
+
|
|
59
|
+
Create `src/lifecycle.tsx`:
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import React from 'react';
|
|
63
|
+
import type { ChildMfeBridge } from '@hai3/react';
|
|
64
|
+
import { ThemeAwareReactLifecycle } from '@hai3/screensets/mfe/handler';
|
|
65
|
+
import { YourScreen } from './screens/YourScreen';
|
|
66
|
+
|
|
67
|
+
class Lifecycle extends ThemeAwareReactLifecycle {
|
|
68
|
+
constructor() {
|
|
69
|
+
super({
|
|
70
|
+
name: '{screensetName}',
|
|
71
|
+
version: '1.0.0',
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async mount(shadowRoot: ShadowRoot, bridge: ChildMfeBridge) {
|
|
76
|
+
const div = document.createElement('div');
|
|
77
|
+
shadowRoot.appendChild(div);
|
|
78
|
+
|
|
79
|
+
// Initialize Tailwind/UIKit styles
|
|
80
|
+
const style = document.createElement('style');
|
|
81
|
+
style.textContent = tailwindStyles; // Import from @hai3/uikit
|
|
82
|
+
shadowRoot.appendChild(style);
|
|
83
|
+
|
|
84
|
+
// Render component
|
|
85
|
+
const root = ReactDOM.createRoot(div);
|
|
86
|
+
root.render(<YourScreen bridge={bridge} />);
|
|
87
|
+
|
|
88
|
+
return { root, div };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export default new Lifecycle();
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## dev:all INTEGRATION (AUTOMATIC)
|
|
96
|
+
|
|
97
|
+
After creating the MFE and running `npm run generate:mfe-manifests`, the `dev:all`
|
|
98
|
+
script auto-discovers your new package — no manual configuration needed.
|
|
99
|
+
|
|
100
|
+
`dev-all.ts` scans `src/mfe_packages/*/package.json` and reads the port from the
|
|
101
|
+
`preview` (or `dev`) script using `--port NNNN`. The new MFE will automatically
|
|
102
|
+
appear in the next `npm run dev:all` run.
|
|
103
|
+
|
|
104
|
+
## VALIDATION
|
|
105
|
+
|
|
106
|
+
After creation:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# Regenerate manifests (required after adding new MFE)
|
|
110
|
+
npm run generate:mfe-manifests
|
|
111
|
+
|
|
112
|
+
# Validate TypeScript
|
|
113
|
+
npm run type-check
|
|
114
|
+
|
|
115
|
+
# Check architecture compliance
|
|
116
|
+
npm run arch:check
|
|
117
|
+
|
|
118
|
+
# Run the dev server (picks up new MFE automatically)
|
|
119
|
+
npm run dev:all
|
|
120
|
+
|
|
121
|
+
# Verify MFE loads at http://localhost:5173
|
|
122
|
+
# Open Studio Overlay (Ctrl+`) and check screenset
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## TROUBLESHOOTING
|
|
126
|
+
|
|
127
|
+
### Issue: MFE not appearing in screenset selector
|
|
128
|
+
- Run `npm run generate:mfe-manifests` to regenerate manifests
|
|
129
|
+
- Check mfe.json manifest is properly exported
|
|
130
|
+
- Verify extensions are registered in manifest
|
|
131
|
+
- Check browser console for errors
|
|
132
|
+
|
|
133
|
+
### Issue: dev:all not picking up MFE port
|
|
134
|
+
- Verify `preview` script has `--port NNNN` (e.g., `"vite preview --port 3010"`)
|
|
135
|
+
- Check port is not in use (`lsof -i :3010`)
|
|
136
|
+
- Restart dev server
|
|
137
|
+
|
|
138
|
+
### Issue: Hot reload not working
|
|
139
|
+
- Verify dev script uses `vite --port` (not `vite build && vite preview`)
|
|
140
|
+
- Check port is not in use
|
|
141
|
+
- Restart dev server
|
|
142
|
+
|
|
143
|
+
### Issue: Redux/useSelector errors
|
|
144
|
+
- MFE must use mock data (no Redux Provider in isolation)
|
|
145
|
+
- Use `useState` for local state management
|
|
146
|
+
- Do not import Redux hooks (@hai3/react)
|
|
147
|
+
|
|
148
|
+
## BEST PRACTICES
|
|
149
|
+
|
|
150
|
+
✅ **DO:**
|
|
151
|
+
- Set `preview` script with `--port NNNN` for port auto-discovery
|
|
152
|
+
- Use mock data with useState for UI-only MFEs
|
|
153
|
+
- Keep MFE logic isolated and simple
|
|
154
|
+
- Use @hai3/uikit components
|
|
155
|
+
- Run `npm run generate:mfe-manifests` after creating the MFE
|
|
156
|
+
|
|
157
|
+
❌ **DON'T:**
|
|
158
|
+
- Import Redux hooks directly
|
|
159
|
+
- Use vite build && vite preview in dev mode
|
|
160
|
+
- Create complex state management in MFE
|
|
161
|
+
- Hardcode ports without updating package.json preview script
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
See also:
|
|
166
|
+
- `/packages/cli/template-sources/mfe-package/` for templates
|
|
167
|
+
- `hai3-new-screenset.md` for screenset creation
|