Esplora il framework single-SPA per creare architetture micro-frontend scalabili e manutenibili. Scopri i vantaggi, l'implementazione e le best practice.
Framework Single-SPA: Una Guida Completa all'Orchestrazione di Micro-Frontend
Nel panorama odierno dello sviluppo web, in rapida evoluzione, i frontend monolitici faticano sempre più a tenere il passo con le esigenze di applicazioni in crescita e team distribuiti. L'architettura a micro-frontend è emersa come una potente soluzione a queste sfide, consentendo agli sviluppatori di costruire interfacce utente complesse come una collezione di componenti indipendenti, distribuibili e manutenibili. Questo approccio favorisce l'autonomia dei team, promuove il riutilizzo del codice e semplifica il processo di sviluppo complessivo. Tra i vari framework disponibili per l'orchestrazione di micro-frontend, single-SPA si distingue come una scelta versatile e robusta.
Cosa sono i Micro-Frontend?
I micro-frontend sono uno stile architetturale in cui un'applicazione frontend viene scomposta in unità più piccole, indipendenti e autonome (micro-frontend). Ciascun micro-frontend può essere sviluppato, distribuito e mantenuto da team separati. Pensalo come una composizione di diverse mini-applicazioni che lavorano insieme per formare un'esperienza utente coesa.
Le caratteristiche principali dei micro-frontend includono:
- Indipendenza dalla Tecnologia: Ciascun micro-frontend può essere costruito utilizzando diversi framework e tecnologie (React, Angular, Vue.js, ecc.)
- Distribuibilità Indipendente: I micro-frontend possono essere distribuiti indipendentemente senza influenzare altre parti dell'applicazione.
- Team Autonomi: Team diversi possono possedere e mantenere micro-frontend differenti, favorendo l'autonomia e cicli di sviluppo più rapidi.
- Riusabilità del Codice: Componenti e librerie comuni possono essere condivisi tra i micro-frontend.
- Scalabilità e Manutenibilità Migliorate: Unità più piccole e indipendenti sono più facili da scalare, mantenere e aggiornare rispetto a una grande applicazione monolitica.
Perché Scegliere Single-SPA?
Single-SPA è un framework JavaScript che facilita l'orchestrazione di più applicazioni JavaScript (micro-frontend) all'interno di una singola pagina del browser. Non prescrive alcuno stack tecnologico specifico per i micro-frontend stessi, permettendo ai team di scegliere gli strumenti più adatti alle loro esigenze. Questo framework agisce come un meta-framework, fornendo l'infrastruttura per caricare, scaricare e gestire il ciclo di vita dei diversi micro-frontend.
Ecco perché single-SPA è una scelta popolare per l'orchestrazione di micro-frontend:
- Indipendenza dal Framework: single-SPA può essere utilizzato con praticamente qualsiasi framework JavaScript, inclusi React, Angular, Vue.js, Svelte e altri. Questa flessibilità permette ai team di adottare i micro-frontend in modo incrementale senza riscrivere le loro applicazioni esistenti.
- Adozione Graduale: Puoi migrare gradualmente un'applicazione monolitica a un'architettura a micro-frontend, iniziando con funzionalità piccole e isolate.
- Condivisione del Codice: single-SPA permette di condividere codice e dipendenze tra i micro-frontend, riducendo la ridondanza e migliorando la coerenza.
- Lazy Loading: I micro-frontend vengono caricati su richiesta, migliorando il tempo di caricamento iniziale della pagina e le prestazioni complessive.
- Distribuzione Semplificata: La distribuzione indipendente dei micro-frontend consente cicli di rilascio più rapidi e un rischio ridotto.
- Gestione Robusta del Ciclo di Vita: single-SPA fornisce un ciclo di vita ben definito per ogni micro-frontend, garantendo che vengano inizializzati, montati, smontati e distrutti correttamente.
Concetti Chiave in Single-SPA
Per utilizzare efficacemente single-SPA, è fondamentale comprenderne i concetti fondamentali:
- Configurazione di Single-SPA (Single-SPA Config): Il file JavaScript principale che avvia l'applicazione single-SPA. È responsabile della registrazione dei micro-frontend e della definizione della logica di routing. Questo include spesso il componente radice che gestisce tutto.
- Micro-frontend: Applicazioni JavaScript indipendenti che vengono registrate con la configurazione di single-SPA. Ciascun micro-frontend è responsabile del rendering di una parte specifica dell'interfaccia utente.
- Parcel: Componenti riutilizzabili che possono essere condivisi tra i micro-frontend. I parcel sono utili per creare elementi UI comuni o logica di business necessaria in più parti dell'applicazione.
- Configurazione Radice (Root Config): Lo "shell" dell'applicazione principale che carica e orchestra i micro-frontend. È responsabile della gestione del routing, della gestione dello stato globale e della comunicazione tra i micro-frontend.
- Funzioni di Attività (Activity Functions): Funzioni JavaScript che determinano quando un micro-frontend dovrebbe essere attivo (montato) o inattivo (smontato). Queste si basano tipicamente sui percorsi URL o su altri stati dell'applicazione.
Implementare Single-SPA: Una Guida Passo-Passo
Vediamo un esempio base di come impostare un'applicazione single-SPA con due micro-frontend: uno costruito con React e l'altro con Vue.js.
Passo 1: Impostare la Configurazione di Single-SPA
Per prima cosa, crea una nuova directory per la tua applicazione single-SPA e inizializza un progetto Node.js:
mkdir single-spa-example
cd single-spa-example
npm init -y
Successivamente, installa le dipendenze necessarie:
npm install single-spa import-map-overrides
Crea un file `index.html` nella directory principale:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Single-SPA Example</title>
<meta name="importmap-type" content="systemjs-importmap">
<script type="systemjs-importmap">
{
"imports": {
"single-spa": "https://cdn.jsdelivr.net/npm/single-spa@5.9.0/lib/single-spa.min.js",
"react": "https://cdn.jsdelivr.net/npm/react@16.13.1/umd/react.production.min.js",
"react-dom": "https://cdn.jsdelivr.net/npm/react-dom@16.13.1/umd/react-dom.production.min.js",
"vue": "https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.min.js"
}
}
</script>
<script src="https://cdn.jsdelivr.net/npm/import-map-overrides@2.2.0/dist/import-map-overrides.js"></script>
<script src="https://cdn.jsdelivr.net/npm/systemjs@6.8.3/dist/system.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/systemjs@6.8.3/dist/extras/named-exports.js"></script>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<script>
System.import('single-spa-config');
</script>
<import-map-overrides-full show-when-local-storage="devtools"></import-map-overrides-full>
</body>
</html>
Questo file `index.html` imposta il caricatore di moduli SystemJS, le import map e la configurazione di single-SPA. Le import map definiscono gli URL per le dipendenze utilizzate dai micro-frontend.
Crea un file `single-spa-config.js`:
import * as singleSpa from 'single-spa';
singleSpa.registerApplication(
'react-app',
() => System.import('react-app'),
location => location.pathname.startsWith('/react')
);
singleSpa.registerApplication(
'vue-app',
() => System.import('vue-app'),
location => location.pathname.startsWith('/vue')
);
singleSpa.start();
Questo file registra due micro-frontend: `react-app` e `vue-app`. La `activityFunction` determina quando ciascun micro-frontend deve essere attivo in base all'URL.
Passo 2: Creare il Micro-Frontend React
Crea una nuova directory per il micro-frontend React:
mkdir react-app
cd react-app
npx create-react-app .
npm install single-spa-react
Modifica il file `src/index.js` per utilizzare `single-spa-react`:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import singleSpaReact from 'single-spa-react';
const lifecycles = singleSpaReact({
React,
ReactDOM,
rootComponent: App,
errorBoundary(err, info, props) {
// Customize the root error boundary for your microfrontend here.
return (<h1>Error</h1>);
},
});
export const { bootstrap, mount, unmount } = lifecycles;
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
Crea un file `public/index.html` (se non esiste) e assicurati che il div `root` sia presente:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
Modifica `App.js` per mostrare un testo personalizzato per verificare facilmente il nostro lavoro:
import React from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Questo è il <b>Micro-Frontend React</b>!
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
Esegui il build del micro-frontend React:
npm run build
Rinomina la directory `build` in `react-app` e posizionala nella radice dell'applicazione single-SPA. Quindi, all'interno della directory `react-app` crea un file `react-app.js` con il contenuto del file `build/static/js`. Se ci sono più file js nella directory `static/js`, includi anche quelli.
Aggiorna l'import map in `index.html` per puntare al micro-frontend React:
{
"imports": {
"single-spa": "https://cdn.jsdelivr.net/npm/single-spa@5.9.0/lib/single-spa.min.js",
"react": "https://cdn.jsdelivr.net/npm/react@16.13.1/umd/react.production.min.js",
"react-dom": "https://cdn.jsdelivr.net/npm/react-dom@16.13.1/umd/react-dom.production.min.js",
"vue": "https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.min.js",
"react-app": "/react-app/react-app.js"
}
}
Passo 3: Creare il Micro-Frontend Vue.js
Crea una nuova directory per il micro-frontend Vue.js:
mkdir vue-app
cd vue-app
npx @vue/cli create .
npm install single-spa-vue --save
Durante la configurazione della CLI di Vue, scegli il preset predefinito o personalizzalo secondo le necessità.
Modifica il file `src/main.js` per utilizzare `single-spa-vue`:
import Vue from 'vue'
import App from './App.vue'
import singleSpaVue from 'single-spa-vue';
Vue.config.productionTip = false
const vueLifecycles = singleSpaVue({
Vue,
appOptions: {
el: '#vue-app',
render: h => h(App)
}
});
export const bootstrap = vueLifecycles.bootstrap;
export const mount = vueLifecycles.mount;
export const unmount = vueLifecycles.unmount;
Modifica `App.vue` per mostrare un testo personalizzato per verificare facilmente il nostro lavoro:
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<p>Questo è il <b>Micro-Frontend Vue</b>!</p>
<HelloWorld msg="Welcome to Your Vue.js App"/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
components: {
HelloWorld
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
</style>
Esegui il build del micro-frontend Vue.js:
npm run build
Rinomina la directory `dist` in `vue-app` e posizionala nella radice dell'applicazione single-SPA. Quindi, all'interno della directory `vue-app` crea un file `vue-app.js` con il contenuto del file `dist/js/app.js`. Se ci sono più file js nella directory `dist/js`, includi anche quelli.
Aggiorna l'import map in `index.html` per puntare al micro-frontend Vue.js:
{
"imports": {
"single-spa": "https://cdn.jsdelivr.net/npm/single-spa@5.9.0/lib/single-spa.min.js",
"react": "https://cdn.jsdelivr.net/npm/react@16.13.1/umd/react.production.min.js",
"react-dom": "https://cdn.jsdelivr.net/npm/react-dom@16.13.1/umd/react-dom.production.min.js",
"vue": "https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.min.js",
"react-app": "/react-app/react-app.js",
"vue-app": "/vue-app/vue-app.js"
}
}
Passo 4: Eseguire l'Applicazione
Servi il file `index.html` usando un semplice server HTTP. Puoi usare uno strumento come `http-server`:
npm install -g http-server
http-server -c-1
Naviga su `http://localhost:8080/react` per vedere il micro-frontend React e su `http://localhost:8080/vue` per vedere il micro-frontend Vue.js.
Considerazioni Importanti:
- Questo esempio utilizza un routing semplice basato su prefissi URL. Per scenari di routing più complessi, considera l'uso di una libreria di routing dedicata come `single-spa-router`.
- In un ambiente di produzione, tipicamente serviresti i micro-frontend da una CDN o da un altro servizio di hosting di asset statici.
- Questo esempio utilizza le import map per la gestione delle dipendenze. Considera l'uso di uno strumento di build come Webpack o Parcel per pacchettizzare i tuoi micro-frontend per la produzione.
Tecniche Avanzate di Single-SPA
Una volta impostata un'applicazione single-SPA di base, puoi esplorare tecniche più avanzate per migliorare la scalabilità e la manutenibilità della tua architettura.
Condividere Codice con i Parcel
I Parcel ti permettono di condividere componenti e logica riutilizzabili tra i micro-frontend. Questo può aiutare a ridurre la duplicazione del codice e a migliorare la coerenza in tutta l'applicazione.
Per creare un parcel, puoi usare la funzione `singleSpa.mountRootParcel`:
import * as singleSpa from 'single-spa';
import React from 'react';
import ReactDOM from 'react-dom';
function MyParcel(props) {
return (<div>Ciao dal Parcel! {props.name}</div>);
}
const parcel = singleSpa.mountRootParcel(() => {
return Promise.resolve({
bootstrap: () => Promise.resolve(),
mount: (props) => {
ReactDOM.render(<MyParcel name={props.name} />, document.getElementById('parcel-container'));
return Promise.resolve();
},
unmount: () => {
ReactDOM.unmountComponentAtNode(document.getElementById('parcel-container'));
return Promise.resolve();
},
});
});
// Per montare il parcel:
parcel.mount({ name: 'Esempio' });
Comunicazione tra Micro-frontend
I micro-frontend spesso hanno bisogno di comunicare tra loro per condividere dati o attivare azioni. Ci sono diversi modi per ottenere questo risultato:
- Stato Globale Condiviso: Usa una libreria di gestione dello stato globale come Redux o Vuex per condividere dati tra i micro-frontend.
- Eventi Personalizzati: Usa eventi DOM personalizzati per trasmettere messaggi tra i micro-frontend.
- Chiamate Dirette di Funzioni: Esporta funzioni da un micro-frontend e importale in un altro. Questo approccio richiede un'attenta coordinazione per evitare dipendenze e riferimenti circolari.
- Message Broker: Implementa un pattern di message broker usando una libreria come RabbitMQ o Kafka per disaccoppiare i micro-frontend e abilitare la comunicazione asincrona.
Autenticazione e Autorizzazione
Implementare l'autenticazione e l'autorizzazione in un'architettura a micro-frontend può essere una sfida. Ecco alcuni approcci comuni:
- Autenticazione Centralizzata: Usa un servizio di autenticazione centrale per gestire il login e l'autenticazione degli utenti. Il servizio di autenticazione può emettere token che vengono utilizzati per autenticare le richieste ai micro-frontend.
- Modulo di Autenticazione Condiviso: Crea un modulo di autenticazione condiviso utilizzato da tutti i micro-frontend. Questo modulo può gestire la gestione dei token e la sessione utente.
- API Gateway: Usa un API gateway per gestire l'autenticazione e l'autorizzazione per tutte le richieste ai micro-frontend. L'API gateway può verificare i token e applicare le policy di controllo degli accessi.
Vantaggi dell'Architettura a Micro-Frontend con Single-SPA
- Maggiore Autonomia dei Team: Team indipendenti possono sviluppare e distribuire micro-frontend senza impattare altri team. Ciò favorisce l'autonomia e cicli di sviluppo più rapidi.
- Scalabilità Migliorata: I micro-frontend possono essere scalati indipendentemente, permettendoti di ottimizzare l'allocazione delle risorse e gestire un aumento del traffico.
- Manutenibilità Potenziata: Unità più piccole e indipendenti sono più facili da mantenere e aggiornare rispetto a una grande applicazione monolitica.
- Diversità Tecnologica: I team possono scegliere lo stack tecnologico migliore per il loro micro-frontend, consentendo maggiore flessibilità e innovazione.
- Rischio Ridotto: La distribuzione indipendente dei micro-frontend riduce il rischio di implementare modifiche e semplifica le procedure di rollback.
- Migrazione Graduale: Puoi migrare gradualmente un'applicazione monolitica a un'architettura a micro-frontend senza richiedere una riscrittura completa.
Sfide dell'Architettura a Micro-Frontend
Sebbene i micro-frontend offrano molti vantaggi, introducono anche alcune sfide:
- Complessità Aumentata: Gestire più micro-frontend può essere più complesso che gestire una singola applicazione monolitica.
- Overhead di Comunicazione: Coordinare la comunicazione tra i micro-frontend può essere impegnativo.
- Complessità di Distribuzione: Distribuire più micro-frontend può essere più complesso che distribuire una singola applicazione.
- Coerenza: Mantenere un'esperienza utente coerente tra i vari micro-frontend può essere difficile.
- Duplicazione: Senza un'attenta pianificazione, codice e dipendenze possono essere duplicati tra i micro-frontend.
- Overhead Operativo: Impostare e gestire l'infrastruttura per più micro-frontend può aumentare l'overhead operativo.
Best Practice per la Creazione di Micro-Frontend con Single-SPA
Per implementare con successo un'architettura a micro-frontend con single-SPA, segui queste best practice:
- Definisci Confini Chiari: Definisci chiaramente i confini tra i micro-frontend per minimizzare le dipendenze e l'overhead di comunicazione.
- Stabilisci una Guida di Stile Condivisa: Crea una guida di stile condivisa per garantire un'esperienza utente coerente tra i micro-frontend.
- Automatizza la Distribuzione: Automatizza il processo di distribuzione per semplificare l'implementazione dei micro-frontend.
- Monitora le Prestazioni: Monitora le prestazioni di ogni micro-frontend per identificare e risolvere i problemi.
- Usa un Sistema di Logging Centralizzato: Usa un sistema di logging centralizzato per aggregare i log da tutti i micro-frontend e semplificare la risoluzione dei problemi.
- Implementa una Gestione Robusta degli Errori: Implementa una gestione robusta degli errori per evitare che errori in un micro-frontend influenzino gli altri.
- Documenta la Tua Architettura: Documenta la tua architettura a micro-frontend per assicurarti che tutti nel team capiscano come funziona.
- Scegli la Giusta Strategia di Comunicazione: Seleziona la strategia di comunicazione appropriata in base alle esigenze della tua applicazione.
- Dai Priorità alle Prestazioni: Ottimizza le prestazioni di ogni micro-frontend per garantire un'esperienza utente veloce e reattiva.
- Considera la Sicurezza: Implementa le best practice di sicurezza per proteggere la tua architettura a micro-frontend dalle vulnerabilità.
- Adotta una Cultura DevOps: Promuovi una cultura DevOps per favorire la collaborazione tra i team di sviluppo e operazioni.
Casi d'Uso per Single-SPA e Micro-Frontend
Single-SPA e i micro-frontend sono adatti a una varietà di casi d'uso, tra cui:
- Applicazioni Grandi e Complesse: I micro-frontend possono aiutare a scomporre applicazioni grandi e complesse in unità più piccole e gestibili.
- Organizzazioni con Team Multipli: I micro-frontend possono consentire a team diversi di lavorare in modo indipendente su parti diverse dell'applicazione. Ad esempio, in un'azienda di e-commerce globale, un team potrebbe concentrarsi sul catalogo prodotti (con sede, ad esempio, in Germania), mentre un altro gestisce il carrello degli acquisti (con sede, ad esempio, in India), e un terzo si occupa degli account utente (con sede, ad esempio, negli Stati Uniti).
- Migrazione di Applicazioni Legacy: I micro-frontend possono essere utilizzati per migrare gradualmente applicazioni legacy a un'architettura più moderna.
- Costruzione di Soluzioni Platform-as-a-Service (PaaS): I micro-frontend possono essere usati per costruire soluzioni PaaS che permettono agli sviluppatori di creare e distribuire le proprie applicazioni.
- Esperienze Utente Personalizzate: Diversi micro-frontend possono essere utilizzati per fornire esperienze utente personalizzate in base a ruoli, preferenze o posizione dell'utente. Immagina un sito di notizie che carica dinamicamente diversi moduli di contenuto in base agli interessi e alla cronologia di lettura dell'utente.
Il Futuro dei Micro-Frontend
L'architettura a micro-frontend continua ad evolversi, con nuovi strumenti e tecniche che emergono per affrontare le sfide della costruzione e gestione di applicazioni frontend distribuite. Alcune tendenze chiave da tenere d'occhio includono:
- Web Component: I Web Component sono uno standard per la creazione di elementi UI riutilizzabili che possono essere usati in qualsiasi applicazione web. Possono essere utilizzati per costruire micro-frontend indipendenti dal framework e facilmente integrabili in diverse applicazioni.
- Module Federation: La Module Federation è una funzionalità di Webpack che permette di condividere codice e dipendenze tra diverse build di Webpack. Può essere utilizzata per costruire micro-frontend debolmente accoppiati e distribuibili in modo indipendente.
- Server-Side Rendering (SSR): Il rendering lato server può migliorare le prestazioni e la SEO delle applicazioni a micro-frontend. L'SSR può essere usato per renderizzare l'HTML iniziale del micro-frontend sul server, riducendo la quantità di JavaScript che deve essere scaricata ed eseguita sul client.
- Edge Computing: L'edge computing può essere utilizzato per distribuire i micro-frontend più vicino all'utente, riducendo la latenza e migliorando le prestazioni. L'edge computing può anche abilitare nuovi casi d'uso per i micro-frontend, come l'accesso offline e l'elaborazione dei dati in tempo reale.
Conclusione
Single-SPA è un framework potente per costruire architetture a micro-frontend scalabili, manutenibili e flessibili. Abbracciando i principi dei micro-frontend e sfruttando le capacità di single-SPA, le organizzazioni possono potenziare i loro team, accelerare i cicli di sviluppo e offrire esperienze utente eccezionali. Sebbene i micro-frontend introducano complessità, l'adozione di best practice, una pianificazione attenta e la scelta degli strumenti giusti sono essenziali per il successo. Poiché il panorama dei micro-frontend continua ad evolversi, rimanere informati sulle nuove tecnologie e tecniche sarà cruciale per costruire applicazioni web moderne e resilienti.