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.

Font

Il fragment dichiara 'Inter' come prima scelta nello stack font-family, con fallback a system-ui e font di sistema. In modalità fetch server-side il font non viene caricato dal fragment: questo evita richieste duplicate e collisioni con eventuali @font-face già presenti nella pagina ospite.

Se vuoi il rendering canonico con Inter, è l'host a doverla includere (variabile o weights 400/600/700, subset latin sufficiente). Esempio self-hosted:

<link rel="preload" as="font" type="font/woff2" crossorigin
      href="/fonts/InterVariable.woff2" />
<style>
  @font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('/fonts/InterVariable.woff2') format('woff2-variations');
  }
</style>

Senza questo, il browser renderizza con il primo fallback disponibile — layout e dimensioni restano corretti (lo stack è metrica-compatibile).

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.

In questa modalità il fragment carica Inter da /fonts/InterVariable.woff2 (preload + @font-face iniettati a runtime solo dentro l'iframe). Quando il font è pronto viene rispedito un fragment:resize forzato per assorbire l'eventuale cambio di metrica.

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