Alpine.store in Magento 2 con Hyvä: come condividere lo stato tra componenti Alpine.js

Uno degli aspetti più interessanti dello sviluppo frontend con Magento 2 e Hyvä Themes è la possibilità di realizzare interfacce dinamiche utilizzando JavaScript leggero, senza ricorrere a framework complessi come React o Vue.
Hyvä utilizza Alpine.js per gestire l’interattività dei componenti frontend. Nella maggior parte dei casi, la direttiva x-data è sufficiente per implementare menu, modali, selettori e altri elementi dinamici.
Ma cosa succede quando più componenti, distribuiti in template Magento differenti, devono condividere le stesse informazioni?
Pensiamo a un e-commerce che deve visualizzare contemporaneamente:
- Una barra che indica quanto manca per ottenere un regalo.
- Un messaggio promozionale nel carrello.
- Un popup per scegliere un prodotto omaggio.
- Un badge sui prodotti che partecipano alla promozione.
Questi elementi possono trovarsi in blocchi Magento completamente indipendenti.
Una possibile soluzione consiste nell’utilizzare eventi JavaScript personalizzati. Tuttavia, quando il numero di componenti aumenta, la gestione degli eventi può diventare complessa.
Alpine.store() offre un’alternativa: uno stato globale reattivo, condiviso tra tutti i componenti Alpine.js presenti nella pagina.
Vediamo come funziona e come integrarlo correttamente in un progetto Magento 2 con Hyvä.
1. Cos’è Alpine.store e come funziona
Alpine.store() è una funzionalità disponibile in Alpine.js 3 che permette di definire oggetti JavaScript globali e reattivi.
A differenza di x-data, che crea uno stato associato a uno specifico elemento DOM, uno store può essere utilizzato da qualsiasi componente Alpine.js.
Consideriamo questo esempio:
document.addEventListener('alpine:init', () => {
Alpine.store('cart', {
itemsCount: 0,
increment() {
this.itemsCount++;
}
});
});
Abbiamo creato uno store chiamato cart, contenente:
- Una proprietà reattiva
itemsCount. - Un metodo
increment()che modifica lo stato.
Per accedere allo store da un componente HTML utilizziamo $store.
<div x-data>
Prodotti nel carrello:
<span x-text="$store.cart.itemsCount"></span>
</div>
Un secondo componente può modificare lo stesso valore:
<div x-data>
<button
type="button"
@click="$store.cart.increment()"
>
Incrementa
</button>
</div>
Quando viene premuto il pulsante, il contatore del primo componente viene aggiornato automaticamente.
Non è necessario:
- Cercare gli elementi con
document.querySelector(). - Generare eventi personalizzati.
- Implementare listener per sincronizzare i componenti.
- Aggiornare manualmente il DOM.
Alpine.js gestisce automaticamente la propagazione delle modifiche.
Differenza tra x-data e Alpine.store
La distinzione principale riguarda l’ambito dello stato.
| Caratteristica | x-data | Alpine.store |
|---|---|---|
| Ambito | Componente e discendenti | Globale nella pagina |
| Reattività | Sì | Sì |
| Condivisione tra componenti indipendenti | Non diretta | Sì |
| Inizializzazione | Attributo HTML o Alpine.data | Alpine.store |
| Utilizzo ideale | Stato locale | Stato condiviso |
| Durata | Ciclo di vita del componente | Ciclo di vita della pagina |
La regola architetturale è semplice:
Utilizziamo x-data quando lo stato appartiene a un componente. Utilizziamo Alpine.store() quando lo stato deve essere condiviso tra componenti indipendenti.
Non è necessario trasformare ogni componente Alpine.js in uno store globale.
2. Perché Alpine.store è particolarmente utile in Magento 2 con Hyvä
Magento 2 utilizza un sistema di layout XML e blocchi PHP per costruire le pagine frontend.
In un progetto Hyvä possiamo avere diversi template:
Magento_Theme/
templates/
html/
header.phtml
Magento_Checkout/
templates/
cart/
cart.phtml
Vendor_Promotion/
templates/
promo-banner.phtml
gift-selector.phtml
product-badge.phtml
Questi template possono essere renderizzati in posizioni differenti della pagina.
Ogni template può contenere un proprio componente Alpine.js:
<div x-data="initPromoBanner()">
...
</div>
<div x-data="initGiftSelector()">
...
</div>
<div x-data="initProductBadge()">
...
</div>
Il problema nasce quando tutti devono conoscere lo stesso stato applicativo.
Per esempio:
{
cartTotal: 85,
freeGiftThreshold: 100,
selectedGift: null,
isEligible: false
}
Una soluzione tradizionale potrebbe utilizzare CustomEvent e window.addEventListener() per distribuire le informazioni.
Con Alpine.store() possiamo invece centralizzare i dati:
Alpine.store('promotion', {
cartTotal: 0,
threshold: 100,
selectedGift: null,
get isEligible() {
return this.cartTotal >= this.threshold;
}
});
Ogni componente può accedere direttamente allo stato condiviso:
<div x-data>
<span
x-show="$store.promotion.isEligible"
>
Hai diritto a un regalo!
</span>
</div>
Questa soluzione è particolarmente interessante per le funzionalità frontend che coinvolgono più blocchi Magento.
3. Esempio pratico: promozione con regalo al raggiungimento di una soglia
Realizziamo una funzionalità per Magento 2 con Hyvä.
Requisito funzionale: quando il subtotale del carrello raggiunge 100 euro, il cliente può selezionare un prodotto omaggio.
L’interfaccia prevede quattro componenti:
- Banner promozionale.
- Indicatore di avanzamento della spesa.
- Drawer per la selezione del regalo.
- Messaggio nel carrello.
Tutti i componenti devono utilizzare le stesse informazioni.
3.1 Architettura della soluzione
Possiamo rappresentare il flusso nel seguente modo:
Magento 2
|
|
Dati del carrello
|
v
Evento update-totals
|
v
+-------------------+
| Alpine.store |
| promotion |
+-------------------+
|
+--------+--------+
| | |
v v v
Banner Progress Drawer
Bar
|
v
Cart Message
Lo store rappresenta la fonte condivisa dello stato frontend.
Ogni componente legge le proprietà che gli interessano e reagisce automaticamente alle modifiche.
Importante: lo store non deve diventare la fonte autorevole delle regole commerciali.
La validazione della soglia promozionale e dell’effettiva disponibilità del regalo deve essere eseguita anche dal backend Magento.
4. Implementare lo store Alpine.js
Creiamo uno store chiamato promotion.
Per semplicità utilizziamo JavaScript direttamente nel template. In un modulo Magento strutturato possiamo separare la logica in un file dedicato.
document.addEventListener('alpine:init', () => {
if (Alpine.store('promotion')) {
return;
}
Alpine.store('promotion', {
// Configurazione
threshold: 100,
// Stato
cartTotal: 0,
selectedGift: null,
drawerOpen: false,
bannerVisible: true,
// Proprietà calcolate
get isEligible() {
return this.cartTotal >= this.threshold;
},
get remaining() {
return Math.max(
0,
this.threshold - this.cartTotal
);
},
get progress() {
if (this.threshold <= 0) {
return 100;
}
return Math.min(
100,
(this.cartTotal / this.threshold) * 100
);
},
// Azioni
openDrawer() {
this.drawerOpen = true;
},
closeDrawer() {
this.drawerOpen = false;
},
selectGift(gift) {
this.selectedGift = gift;
this.closeDrawer();
},
dismissBanner() {
this.bannerVisible = false;
},
// Sincronizzazione carrello
updateCartTotal(total) {
const previousEligibility = this.isEligible;
this.cartTotal = Number(total) || 0;
if (
!previousEligibility &&
this.isEligible &&
!this.selectedGift
) {
this.openDrawer();
}
if (!this.isEligible) {
this.selectedGift = null;
this.closeDrawer();
}
}
});
});
Perché utilizzare i getter?
Le proprietà:
get isEligible()
get remaining()
get progress()
non rappresentano uno stato indipendente.
Sono valori derivati da altre proprietà.
Per esempio:
get remaining() {
return Math.max(
0,
this.threshold - this.cartTotal
);
}
Se cartTotal passa da 50 a 80, remaining restituisce automaticamente 20.
Non dobbiamo aggiornare manualmente entrambe le proprietà.
Questo approccio riduce il rischio di inconsistenze.
Evitare l’inizializzazione multipla
È importante verificare che lo store non sia già stato registrato:
if (Alpine.store('promotion')) {
return;
}
In questo modo evitiamo di sovrascrivere accidentalmente uno stato già inizializzato.
La protezione è utile soprattutto nei progetti Magento con molti moduli custom e layout XML complessi.
5. Creare un banner promozionale reattivo
Il primo componente visualizza quanto manca per ottenere il regalo.
<div
x-data
x-show="$store.promotion.bannerVisible"
x-cloak
class="bg-blue-50 p-4 rounded-lg"
>
<template x-if="!$store.promotion.isEligible">
<div>
<p>
Aggiungi ancora
<strong
x-text="
hyva.formatPrice(
$store.promotion.remaining
)
"
></strong>
al carrello per ricevere un regalo.
</p>
</div>
</template>
<template x-if="$store.promotion.isEligible">
<div>
<p>
Complimenti! Hai raggiunto
la soglia per ottenere un regalo.
</p>
<button
type="button"
@click="$store.promotion.openDrawer()"
>
Scegli il regalo
</button>
</div>
</template>
</div>
Il componente non contiene logica relativa al calcolo della promozione.
Si limita a leggere lo stato globale.
Questo consente di mantenere il template semplice.
Un vantaggio importante
Possiamo inserire il banner:
- Nell’header.
- Nella pagina prodotto.
- Nel carrello.
- In una sidebar.
Non è necessario duplicare la logica JavaScript.
Tutti i banner utilizzano lo stesso store.
6. Implementare una progress bar condivisa
Una barra di avanzamento permette al cliente di visualizzare quanto manca per raggiungere la soglia.
<div x-data class="w-full">
<div
class="w-full bg-gray-200 rounded-full h-3"
>
<div
class="bg-green-600 h-3 rounded-full"
:style="
`width: ${$store.promotion.progress}%`
"
></div>
</div>
<p class="mt-2 text-sm">
<span
x-text="$store.promotion.progress.toFixed(0)"
></span>%
della soglia raggiunta
</p>
</div>
La progress bar si aggiorna automaticamente quando cambia cartTotal.
Per esempio:
| Subtotale carrello | Avanzamento |
|---|---|
| 20 € | 20% |
| 50 € | 50% |
| 75 € | 75% |
| 100 € | 100% |
| 150 € | 100% |
Il limite massimo viene gestito dal getter:
return Math.min(
100,
(this.cartTotal / this.threshold) * 100
);
In questo modo la barra non supera mai il 100%.
7. Gestire un drawer globale per la selezione del regalo
Supponiamo di voler visualizzare un drawer quando il cliente raggiunge la soglia promozionale.
Il drawer può essere definito in un template indipendente:
<div
x-data
x-show="$store.promotion.drawerOpen"
x-cloak
@keydown.escape.window="
$store.promotion.closeDrawer()
"
class="fixed inset-0 z-50"
>
<div class="absolute inset-0 bg-black/50"></div>
<div
class="absolute right-0 top-0
h-full w-full max-w-md
bg-white p-6 shadow-xl"
role="dialog"
aria-modal="true"
aria-label="Selezione regalo"
>
<div class="flex justify-between items-center">
<h2 class="text-xl font-semibold">
Scegli il tuo regalo
</h2>
<button
type="button"
@click="$store.promotion.closeDrawer()"
aria-label="Chiudi"
>
Chiudi
</button>
</div>
<div class="mt-6">
<!-- Elenco dei regali disponibili -->
</div>
</div>
</div>
Il drawer viene aperto chiamando:
Alpine.store('promotion').openDrawer();
Oppure da qualsiasi componente Alpine:
<button
@click="$store.promotion.openDrawer()"
>
Scegli il regalo
</button>
Il vantaggio è evidente: il componente che apre il drawer non deve conoscere la sua posizione nel DOM.
Questo riduce l’accoppiamento tra i template.
In un’implementazione production-ready è necessario completare il drawer con gestione del focus, ripristino del focus alla chiusura e blocco dello scroll, oltre a collegare la selezione del regalo a un endpoint Magento.
8. Sincronizzare Alpine.store con il carrello Magento 2
Finora abbiamo gestito uno stato JavaScript indipendente.
In un progetto reale, però, il subtotale deve essere aggiornato quando cambia il carrello Magento.
Hyvä espone eventi frontend utilizzabili per sincronizzare i componenti.
Uno degli eventi interessanti è:
update-totals
Questo evento viene utilizzato nella gestione dei totali del carrello Hyvä.
Possiamo intercettarlo e aggiornare lo store.
window.addEventListener('update-totals', (event) => {
const totalsData = event.detail?.data;
if (!totalsData) {
return;
}
const subtotalSegment =
totalsData.total_segments?.find(
segment => segment.code === 'subtotal'
);
if (!subtotalSegment) {
return;
}
Alpine.store('promotion').updateCartTotal(
subtotalSegment.value
);
});
Il flusso diventa:
Cliente modifica quantità
|
v
Magento aggiorna carrello
|
v
Hyvä aggiorna i totali
|
v
Evento update-totals
|
v
Alpine.store('promotion')
|
v
Aggiornamento automatico
dei componenti frontend
Attenzione al subtotale utilizzato
Magento può esporre differenti valori economici:
- Subtotale prima degli sconti.
- Subtotale dopo gli sconti.
- Totale comprensivo di imposte.
- Totale escluso imposte.
- Grand total.
La scelta dipende dalle regole della promozione.
Per esempio, se il regalo viene assegnato quando il cliente spende almeno 100 euro dopo gli sconti, utilizzare il subtotale lordo può produrre risultati errati.
La regola deve essere coerente con la validazione backend.
Inoltre, l’evento update-totals non rappresenta necessariamente un meccanismo universale per ogni pagina Magento. Per i componenti presenti fuori dal carrello può essere necessario sincronizzare anche i dati delle sezioni private di Hyvä.
9. Un problema importante: la sostituzione dinamica del DOM in Hyvä
Un aspetto che merita particolare attenzione riguarda il ciclo di vita dei componenti.
In alcune operazioni, Hyvä può sostituire dinamicamente porzioni del DOM.
Per esempio, dopo una modifica al carrello può essere utilizzata una funzione come:
hyva.replaceDomElement()
Questo significa che determinati elementi HTML vengono rimossi e sostituiti.
Se un listener è registrato all’interno di un elemento che viene distrutto, anche il componente Alpine associato può cessare di funzionare.
Lo store globale, invece, continua a esistere.
Perché?
Perché Alpine.store() non è associato a un singolo nodo DOM.
Lo store rimane disponibile per tutta la durata della pagina.
Tuttavia, i listener collegati a componenti rimossi dal DOM devono essere registrati nuovamente, oppure collocati in un elemento persistente.
Strategia consigliata
Per le funzionalità condivise:
- Registrare lo store una sola volta.
- Mantenere i listener globali in una posizione persistente.
- Evitare di collocare i listener critici all’interno delle sezioni DOM sostituibili.
- Consentire ai nuovi componenti Alpine di leggere lo store esistente.
Per esempio, un listener dichiarativo può essere associato a un elemento persistente:
<div
x-data
@update-totals.window="
$store.promotion.updateCartTotal(
$event.detail.data.total_segments
.find(segment => segment.code === 'subtotal')
?.value ?? 0
)
"
></div>
Questo elemento dovrebbe essere collocato fuori dalle aree sostituite dinamicamente.
Nel carrello Hyvä, un punto importante da considerare è #maincontent.
Collocare un listener persistente fuori da quest’area evita che venga eliminato durante alcune operazioni di aggiornamento del carrello.
Naturalmente, il comportamento va verificato rispetto alla versione di Hyvä utilizzata e alle personalizzazioni presenti nel progetto.
10. Integrare lo store in un modulo Magento 2
In un progetto strutturato non è consigliabile duplicare lo script di inizializzazione nei vari template.
Una possibile organizzazione è:
app/code/Devlogica/Promotion/
│
├── registration.php
├── etc/
│ └── module.xml
│
└── view/
└── frontend/
├── layout/
│ └── default.xml
│
├── templates/
│ ├── promotion-store.phtml
│ ├── promotion-banner.phtml
│ ├── promotion-progress.phtml
│ └── promotion-drawer.phtml
│
└── web/
Lo store viene inizializzato attraverso un template dedicato.
Gli altri template contengono esclusivamente la logica di presentazione.
Esempio di registrazione nel layout XML
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="before.body.end">
<block
name="devlogica.promotion.store"
template="Devlogica_Promotion::promotion-store.phtml"
/>
</referenceContainer>
</body>
</page>
Il nome del container e la posizione effettiva devono essere verificati rispetto al layout del tema utilizzato.
L’obiettivo è registrare lo store una sola volta e renderlo disponibile ai componenti che ne hanno bisogno.
Compatibilità con Content Security Policy
Nelle versioni moderne di Hyvä è importante considerare anche le regole CSP.
Quando utilizziamo JavaScript inline in un template .phtml, dobbiamo adottare il meccanismo di registrazione previsto dalla versione di Hyvä installata.
Un esempio, nei progetti che supportano HyvaCsp, è:
<?php
/** @var \Hyva\Theme\ViewModel\HyvaCsp $hyvaCsp */
?>
<script>
document.addEventListener('alpine:init', () => {
if (Alpine.store('promotion')) {
return;
}
Alpine.store('promotion', {
threshold: 100,
cartTotal: 0
});
});
</script>
<?php $hyvaCsp->registerInlineScript(); ?>
La registrazione CSP deve essere verificata in funzione della versione del tema e della configurazione del progetto.
11. Alpine.store oppure eventi JavaScript?
Una domanda importante riguarda la scelta tra uno store globale e gli eventi personalizzati.
Hyvä utilizza frequentemente eventi JavaScript per comunicare tra componenti.
Per esempio:
window.dispatchEvent(
new CustomEvent('promotion-updated', {
detail: {
cartTotal: 120
}
})
);
Un componente può intercettare l’evento:
<div
x-data="{ total: 0 }"
@promotion-updated.window="
total = $event.detail.cartTotal
"
>
<span x-text="total"></span>
</div>
Questo approccio è perfettamente valido.
Tuttavia, esiste una differenza architetturale.
Gli eventi comunicano che qualcosa è accaduto. Gli store rappresentano lo stato corrente dell’applicazione.
Consideriamo due casi.
Caso A: notifica di un’operazione
Un prodotto è stato aggiunto al carrello.
window.dispatchEvent(
new CustomEvent('product-added')
);
In questo scenario un evento è appropriato.
Caso B: stato condiviso
Cinque componenti devono sapere se il cliente ha raggiunto la soglia per ricevere un regalo.
In questo caso uno store globale può essere più semplice.
Alpine.store('promotion').isEligible
Non dobbiamo propagare manualmente il valore a ogni componente.
Quando scegliere una soluzione
| Scenario | Soluzione consigliata |
|---|---|
| Apertura di un menu locale | x-data |
| Stato di una singola modale | x-data |
| Notifica di aggiunta al carrello | CustomEvent |
| Stato condiviso di una promozione | Alpine.store |
| Preferenze UI condivise | Alpine.store |
| Comunicazione con API Magento | Fetch API + stato Alpine |
| Validazione delle regole commerciali | Backend Magento |
Le due tecniche non sono alternative assolute.
In molte applicazioni Hyvä, la soluzione migliore consiste nell’utilizzare eventi per ricevere notifiche e Alpine.store per mantenere uno stato condiviso.
12. Errori comuni nell’utilizzo di Alpine.store con Magento 2
12.1 Utilizzare lo store per qualsiasi componente
Non ogni stato deve essere globale.
Un semplice accordion può essere implementato così:
<div x-data="{ open: false }">
<button @click="open = !open">
Dettagli prodotto
</button>
<div x-show="open">
Informazioni aggiuntive
</div>
</div>
Creare uno store globale per questa funzionalità introdurrebbe complessità inutile.
12.2 Registrare più volte lo stesso store
Se più template inizializzano lo stesso store, si rischia di sovrascrivere lo stato.
Utilizzare una registrazione centralizzata e un controllo preventivo:
if (!Alpine.store('promotion')) {
Alpine.store('promotion', {
cartTotal: 0
});
}
12.3 Considerare lo store una fonte dati persistente
Uno store Alpine.js esiste nella memoria JavaScript della pagina.
Quando il browser esegue una nuova navigazione completa, lo store viene ricreato.
Non sostituisce:
- Il database Magento.
- La sessione cliente.
- Il carrello persistente.
- Le API backend.
Lo store è uno strumento per gestire lo stato frontend.
12.4 Salvare informazioni sensibili nello store
Le proprietà di uno store sono accessibili dal codice JavaScript della pagina.
Non dobbiamo utilizzare Alpine.store per memorizzare:
- Password.
- Token riservati.
- Credenziali API.
- Informazioni sensibili non destinate al browser.
12.5 Utilizzare lo stato frontend per validare le promozioni
Nel nostro esempio:
get isEligible() {
return this.cartTotal >= this.threshold;
}
La proprietà controlla esclusivamente il comportamento dell’interfaccia.
Un utente potrebbe modificare il valore dello store tramite gli strumenti di sviluppo del browser.
Pertanto, Magento deve verificare nuovamente:
- Il subtotale effettivo.
- La validità della promozione.
- L’idoneità del prodotto omaggio.
- Eventuali limiti di utilizzo.
- La disponibilità del prodotto.
Le regole commerciali devono essere applicate lato server.
13. Performance: Alpine.store migliora le prestazioni?
L’utilizzo di Alpine.store non rende automaticamente un sito Magento più veloce.
Il vantaggio principale riguarda la semplicità della gestione dello stato.
Tuttavia, una buona architettura può contribuire indirettamente alle performance frontend.
Per esempio, centralizzare uno stato condiviso può evitare:
- Duplicazione della logica JavaScript.
- Listener ridondanti.
- Sincronizzazioni manuali tra componenti.
- Aggiornamenti DOM non necessari.
- Implementazioni ripetute della stessa funzionalità.
Bisogna comunque evitare store eccessivamente grandi.
Uno store con centinaia di proprietà, molte dipendenze e aggiornamenti frequenti può diventare difficile da mantenere.
Separare gli store per responsabilità
Una possibile architettura è:
Alpine.store('promotion', {
// Stato promozioni
});
Alpine.store('wishlistUi', {
// Stato interfaccia wishlist
});
Alpine.store('navigation', {
// Stato navigazione
});
È preferibile rispetto a uno store monolitico che gestisce ogni funzionalità del frontend.
Anche la denominazione degli store è importante.
In un progetto Magento con molti moduli di terze parti, utilizzare nomi sufficientemente specifici riduce il rischio di collisioni.
14. Testing e debugging degli store Alpine.js
Durante lo sviluppo possiamo ispezionare direttamente lo stato dalla console del browser.
Per esempio:
Alpine.store('promotion')
Per verificare la soglia:
Alpine.store('promotion').threshold
Per modificare il subtotale:
Alpine.store('promotion').updateCartTotal(120)
Per verificare l’idoneità:
Alpine.store('promotion').isEligible
Il risultato dovrebbe essere:
true
Possiamo anche verificare il comportamento della progress bar:
Alpine.store('promotion').progress
Risultato:
100
Test funzionali consigliati
Prima di distribuire la funzionalità in produzione, è opportuno verificare almeno questi scenari:
| Test | Risultato atteso |
|---|---|
| Carrello sotto la soglia | Promozione non disponibile |
| Carrello raggiunge la soglia | Promozione disponibile |
| Carrello supera la soglia | Progress bar al 100% |
| Carrello scende sotto la soglia | Promozione disabilitata |
| Apertura drawer | Drawer visibile |
| Chiusura drawer | Drawer nascosto |
| Aggiornamento dinamico carrello | Store sincronizzato |
| Nuova navigazione completa | Stato ricostruito dai dati correnti |
| Aggiornamento della pagina | Nessuna duplicazione dei listener |
Per un progetto Magento complesso, questi scenari possono essere automatizzati con Playwright.
È particolarmente importante verificare che le operazioni di aggiornamento del carrello non provochino la perdita dei listener e che lo stato frontend rimanga coerente con quello del backend.
15. Best practice per Alpine.store nei progetti Hyvä
Quando sviluppiamo funzionalità custom per Magento 2 con Hyvä, consigliamo di seguire alcune regole architetturali.
1. Mantenere locale lo stato che non deve essere condiviso.
Utilizzare x-data per componenti indipendenti.
2. Centralizzare soltanto lo stato realmente globale.
Utilizzare Alpine.store() quando più componenti devono leggere o modificare le stesse informazioni.
3. Separare la logica di business dalla presentazione.
I template .phtml dovrebbero contenere principalmente markup e binding Alpine.
4. Evitare duplicazioni dello stato.
Se un valore può essere calcolato attraverso un getter, non è necessario mantenerne una seconda copia.
5. Gestire correttamente il ciclo di vita del DOM.
Prestare attenzione alle sostituzioni dinamiche effettuate da Hyvä.
6. Considerare sempre la sicurezza.
Le verifiche commerciali e le operazioni sensibili devono essere validate dal backend Magento.
7. Verificare la compatibilità con CSP.
Gli script inline devono rispettare le regole di sicurezza della versione di Hyvä utilizzata.
8. Testare i componenti in modo integrato.
Non basta verificare il singolo componente: è necessario controllare la sincronizzazione tra store, eventi frontend e API Magento.
Conclusioni
Alpine.store() è uno strumento molto utile per sviluppare funzionalità frontend avanzate in Magento 2 con Hyvä Themes.
Permette di condividere uno stato reattivo tra componenti indipendenti, evitando di costruire sistemi complessi di sincronizzazione basati esclusivamente su eventi JavaScript.
I principali vantaggi sono:
- Stato condiviso tra template Magento differenti.
- Aggiornamento automatico dei componenti.
- Riduzione dell’accoppiamento tra blocchi frontend.
- Codice più semplice da mantenere.
- Maggiore riutilizzabilità delle funzionalità.
- Integrazione naturale con Alpine.js e Hyvä.
La scelta tra x-data, eventi personalizzati e Alpine.store() deve comunque dipendere dalle responsabilità del componente.
Una buona architettura frontend non consiste nel rendere globale tutto lo stato, ma nel condividere soltanto quello che deve realmente essere condiviso.
Nei progetti Magento 2 con numerose personalizzazioni, questa distinzione può fare la differenza tra un frontend semplice da evolvere e un sistema difficile da mantenere.
Sviluppo Magento 2 e Hyvä con Devlogica
In Devlogica ci occupiamo di sviluppo Magento 2, personalizzazione di moduli, integrazione con sistemi esterni e realizzazione di frontend basati su Hyvä Themes.
Lavoriamo su architetture frontend e backend con particolare attenzione a performance, manutenibilità e compatibilità con l’ecosistema Magento.
Se stai sviluppando un e-commerce Magento 2 e vuoi implementare funzionalità avanzate con Hyvä e Alpine.js, possiamo aiutarti ad analizzare l’architettura esistente e progettare una soluzione adatta alle esigenze del progetto.
Contattaci per una consulenza tecnica su Magento 2 e Hyvä.
Riferimenti tecnici
L’articolo approfondisce il tema trattato da Anastasiia Bondar in Alpine.store in the Hyvä theme, pubblicato il 23 aprile 2026.
Per ulteriori approfondimenti:
- Alpine.js — documentazione ufficiale di
Alpine.store(). - Alpine.js — documentazione ufficiale di
$store. - Hyvä Themes — documentazione tecnica sul frontend Magento.
- Anastasiia Bondar — Alpine.store in the Hyvä theme.
