Fragments — preview

Internal preview of fragments served by this service. Not indexed.

Come embeddare un fragment

Ogni fragment è esposto come HTML statico raggiungibile via URL pubblico (vedi anteprime sotto). Sono supportate due modalità di integrazione.

1. Fetch server-side preferita

Il consumer scarica l'HTML del fragment dal proprio backend e lo include direttamente nella pagina. È la modalità preferita perché:

Esempio Node / Express:

// build-time o request-time, con cache opportuna
const res = await fetch('https://fragments.example.com/footer/giornaledibrescia/prod/v1.html');
const html = await res.text();
// poi inietti `html` nel template della tua pagina (SSR, Astro, Next, ecc.)

Esempio nginx SSI (con ssi on; attivo sul server):

<!--# include virtual="/proxy/footer/giornaledibrescia/prod/v1.html" -->

Gli stili del fragment sono inline e prefissati con .gdb-footer, quindi non collidono con il CSS della pagina ospite.

2. Iframe + auto-resize alternativa

Da usare quando il fetch server-side non è praticabile (es. integrazioni cross-domain senza backend). Il fragment espone un protocollo postMessage per comunicare al parent l'altezza reale del contenuto, così l'iframe può adattarsi dinamicamente.

Markup minimo lato consumer

<iframe
  src="https://fragments.example.com/footer/giornaledibrescia/prod/v1.html"
  data-fragment-source="footer:giornaledibrescia:v1"
  width="100%"
  height="0"
  style="border: 0; display: block;"
  title="Footer Giornale di Brescia"
></iframe>

Listener per il resize automatico

Il fragment invia messaggi { type: 'fragment:resize', source, height } al parent ogni volta che l'altezza del contenuto cambia (load iniziale, cambio viewport, contenuto dinamico). Il parent ascolta e aggiorna l'altezza dell'iframe corrispondente:

<script>
  window.addEventListener('message', (event) => {
    const data = event.data;
    if (!data || data.type !== 'fragment:resize') return;

    // valida l'origin in produzione
    // if (event.origin !== 'https://fragments.example.com') return;

    const iframes = document.querySelectorAll(
      `iframe[data-fragment-source="${data.source}"]`
    );
    for (const iframe of iframes) {
      // event.source distingue iframe multipli con lo stesso source
      if (iframe.contentWindow === event.source) {
        iframe.height = String(data.height);
        return;
      }
    }
  });
</script>

Handshake (consigliato)

Per evitare race condition (l'iframe può finire di caricare e spedire il primo fragment:resize prima che il listener del parent sia attaccato), il parent può inviare un ping { type: 'fragment:ready' } al contentWindow dell'iframe quando è pronto a ricevere. Il fragment risponde con un re-send forzato dell'altezza corrente:

<script>
  document.addEventListener('DOMContentLoaded', () => {
    document.querySelectorAll('iframe[data-fragment-source]').forEach((iframe) => {
      const ping = () => iframe.contentWindow?.postMessage(
        { type: 'fragment:ready' },
        '*' // o l'origin del fragment in produzione
      );
      iframe.addEventListener('load', ping);
      ping();
    });
  });
</script>

Lo stesso ping è utile per forzare un resize sync dopo cambi di stato lato parent (es. iframe rivelato dopo un display:none, mount tardivo, ecc.).

Sicurezza

Giornale di Brescia

dev /footer/giornaledibrescia/dev/v1.html

staging /footer/giornaledibrescia/staging/v1.html

prod /footer/giornaledibrescia/prod/v1.html