MFE Contracts
Cos'è @pzeta/mfe-contracts
@pzeta/mfe-contracts è la libreria di contratti TypeScript che fa da interfaccia stabile tra la shell Vue e i microfrontend (MFE) caricati dinamicamente. Definisce manifest, lifecycle, routing, permessi e contesto runtime — più un set di composables CRUD riutilizzabili e utilities (loader ESM, debounce, route path helpers).
vue@^3.4. Engine: node>=22.0.0.Funzionalità principali
- Contratti tipizzati —
MFEManifest,MFEModule,MFEContext,MFERoute,MFEComponentper integrazione type-safe - Loader ESM —
MFELoaderper caricamento dinamico dei moduli con cache, retry e validazione manifest - Composables CRUD —
useCrudResource,useCrudView,useDetailForm,useDialog,useErrorToastper ridurre boilerplate nelle viste CRUD degli MFE - Helpers RBAC —
checkPermissions,checkRouteAccess, direttivav-canviacreateCanDirective - Helpers menu —
buildMenuFromManifest,buildSettingsMenuFromManifestsper costruire la navigazione della shell aggregando i manifest - Helpers stili —
mergeTailwindConfig,sanitizeCss,injectCustomStylesper isolamento CSS cross-MFE - Subpath exports — import selettivi (
/types,/loader,/helpers,/composables,/utils) per ottimizzare il bundle size
Architettura
@pzeta/mfe-contracts
├── Types.ts # Manifest · Module · Context · Route · Component · User · EventBus · HttpClient · Config · Theme
├── Loader.ts # MFELoader (caricamento ESM dinamico + cache)
├── Helpers.ts # validateManifest · buildMenu* · checkPermissions · sanitizeCss · ...
├── Directive.ts # createCanDirective (v-can)
├── composables/ # useMfeContext · useCrudResource · useCrudView · useDetailForm
│ # useDialog · useErrorToast
└── utils/ # extractErrorMessage · debounce · stripShellPrefix · buildSettingsFullPath
Modello dei contratti
interface MFEManifest {
name: string
version: string
description: string
icon?: string
routes: MFERoute[]
permissions?: string[]
components?: MFEComponent[]
}
interface MFEModule {
getManifest(): MFEManifest
mount(container: HTMLElement, context: MFEContext): Promise<void>
unmount(): Promise<void>
}
interface MFEContext {
user: MFEUser
basePath: string
http: MFEHttpClient
eventBus: MFEEventBus
theme: MFETheme
onNavigate(path: string): void
// ... config + utilities
}
Sotto-pagine
Composables
Composables Vue 3 per accesso al contesto MFE e pattern CRUD riutilizzabili. Riducono boilerplate in viste lista/dettaglio/dialog/toast.
Helpers
Funzioni di supporto per validazione manifest, costruzione menu, RBAC, gestione stili, routing e utilities pure.
Loader
Caricamento dinamico di microfrontend via ESM import con cache, dedup delle promise, validazione URL e CSS auto-loading.
Types
Contratti TypeScript condivisi tra shell e microfrontend. Manifest, lifecycle, contesto runtime, routing, componenti, utente, HTTP, tema, configurazione.
Quick start
Lato microfrontend — implementa MFEModule
// src/mfe-entry.ts
import { createApp } from 'vue'
import { createRouter, createMemoryHistory } from 'vue-router'
import type { MFEModule, MFEManifest, MFEContext } from '@pzeta/mfe-contracts'
import { MFE_CONTEXT_KEY } from '@pzeta/mfe-contracts'
import App from './App.vue'
import routes from './router/routes'
let app: any = null
export const mfeModule: MFEModule = {
getManifest(): MFEManifest {
return {
name: 'crm-module',
version: '1.0.0',
description: 'Gestione clienti, ticket e pipeline CRM',
icon: 'pi-building',
routes: [
{
path: '/crm/dashboard',
label: 'Dashboard',
icon: 'pi-chart-line',
permission: 'crm.dashboard.read',
meta: { requiresAuth: true, order: 1 }
}
],
permissions: ['crm.read']
}
},
async mount(container, context) {
const router = createRouter({
history: createMemoryHistory(context.basePath),
routes
})
router.afterEach((to) => context.onNavigate(to.path))
app = createApp(App)
app.use(router)
app.provide(MFE_CONTEXT_KEY, context)
app.mount(container)
},
async unmount() {
app?.unmount()
app = null
}
}
export default mfeModule
Lato shell — carica e monta MFE
import { MFELoader, validateManifest, buildMenuFromManifest } from '@pzeta/mfe-contracts'
const loader = new MFELoader()
const module = await loader.load('https://mfe-crm.example.com/index.js')
if (validateManifest(module.getManifest())) {
await module.mount(document.getElementById('mfe-slot')!, mfeContext)
}
Lato componente MFE — composables CRUD
<script setup lang="ts">
import { useCrudView, useMfeContext } from '@pzeta/mfe-contracts/composables'
const ctx = useMfeContext()
const { items, loading, selected, load, save, remove } = useCrudView({
list: () => ctx.http.get('/api/clienti'),
create: (c) => ctx.http.post('/api/clienti', c),
update: (id, c) => ctx.http.put(`/api/clienti/${id}`, c),
remove: (id) => ctx.http.delete(`/api/clienti/${id}`),
})
</script>
Subpath exports
Per minimizzare il bundle dei consumer:
// Solo tipi (zero runtime cost)
import type { MFEManifest, MFEModule } from '@pzeta/mfe-contracts/types'
// Solo loader
import { MFELoader } from '@pzeta/mfe-contracts/loader'
// Solo composables CRUD
import { useCrudView, useDetailForm } from '@pzeta/mfe-contracts/composables'
// Solo utilities
import { debounce, extractErrorMessage } from '@pzeta/mfe-contracts/utils'
// Solo helpers
import { validateManifest, checkPermissions } from '@pzeta/mfe-contracts/helpers'
Quando usare cosa
| Scenario | API |
|---|---|
| Esporre un MFE alla shell | implementa MFEModule + esporta come default |
| Caricare dinamicamente un MFE dalla shell | MFELoader.load(url) |
| Validare un manifest prima del mount | validateManifest / isValidManifest |
| Costruire menu nav dalla lista di manifest | buildMenuFromManifest / buildSettingsMenuFromManifests |
| Check permessi inline in template | direttiva v-can (registrata con createCanDirective) |
| Check permessi programmatico | checkPermissions / checkRouteAccess |
| CRUD list + form completo | useCrudView |
| Solo lista CRUD generica | useCrudResource |
| Form di dettaglio (load/save/reset) | useDetailForm |
| Gestione stato dialog | useDialog |
| Toast errori standardizzato | useErrorToast |
| Accesso al contesto shell dal MFE | useMfeContext (richiede app.provide(MFE_CONTEXT_KEY, ctx)) |
Stack tecnico
- TypeScript ~6.0 — strict, type-first
- Vue 3 Composition API (
>=3.4) - ESM only —
"type": "module", build viatsc - Subpath exports in
package.json - Vitest + happy-dom per i test
ERP functions (formule)
Placeholder per funzioni formula ERP-native registrabili nel motore Fortune Sheet (=ERP.FATTURATO, =ERP.ORDINI, ...). Da implementare nel consumer.
Architettura MFE
Modello architetturale shell + microfrontend, lifecycle mount/unmount, isolation con createMemoryHistory, comunicazione via MFEContext.