Frammenti di contenuto visivo - Consegna con l’URL di pubblicazione visual-content-fragments-deliver-with-the-publish-url

Quando viene pubblicato un frammento di contenuto basato su un modello con uno o più modelli HTML allegati, il HTML di rendering di tale frammento è reso disponibile tramite il livello di pubblicazione di Adobe Experience Manager (AEM) as a Cloud Service in un URL con questa struttura:

https://publish-p<programId>-e<envId>.adobeaemcloud.com/adobe/stable/previewtemplates/contentFragments/<templateId>/<fragmentId>/<variation>.html

Questo URL restituisce un documento HTML autonomo (inclusi CSS e struttura in linea) che può essere incorporato in qualsiasi contesto Web.

NOTE
I frammenti di contenuto visivo sono attualmente in disponibilità limitata.
Se desideri partecipare, invia una richiesta dal tuo indirizzo e-mail ufficiale a experience-production-agent@adobe.com.

Tecniche di incorporamento: panoramica embedding-techniques-overview

Esistono tre approcci distinti per l’utilizzo di HTML da un frammento di contenuto visivo su una pagina host. Ognuno di essi presenta caratteristiche distinte relative all’isolamento dello stile, al comportamento del layout, all’accessibilità e alla complessità.

Elemento in linea
iframe
Elemento personalizzato + DOM ombra
Meccanismo
fetch() l’URL, inserisci la risposta HTML in un <div> tramite innerHTML
<iframe src="publishURL">
Definisci un elemento personalizzato, fetch() il HTML, da inserire in una radice shadow DOM associata
Isolamento stile
Nessuno — il CSS del frammento viene rilasciato nella pagina host e il CSS dell’host influisce sul frammento
Completo: contesto di navigazione separato, isolamento CSS completo
Forte: i blocchi di contorno DOM ombra ospitano una cascata CSS; gli stili di frammento rimangono incapsulati
Partecipazione al layout
Completo: il contenuto fa parte del normale flusso di documenti, risponde al dimensionamento di flexbox/griglia/contenitore
Nessuno — iframe ha dimensioni fisse; richiede il ridimensionamento automatico esplicito di width/height o basato su JS
Completo: l’elemento personalizzato partecipa al flusso normale del documento host come qualsiasi altro elemento DOM
Accessibilità (a11y)
Migliore: il contenuto si trova nella struttura DOM principale, completamente fruibile dagli assistenti vocali e dalla tecnologia per l’accessibilità
Modera — il contesto di navigazione separato può confondere la navigazione dell’utilità di lettura dello schermo; richiede l’attributo title
Buono: il contenuto si trova all’interno dello stesso documento; il DOM ombra è fruibile dalle moderne tecnologie per l’accessibilità
SEO
Scarso — il contenuto caricato tramite JS fetch() non è indicizzato dalla maggior parte dei crawler
Scarso: il contenuto dell’iframe generalmente non è indicizzato nel contesto della pagina padre
Scarso: come in linea; il contenuto recuperato da JS non è sottoponibile a ricerca per indicizzazione
runtime JavaScript
Condiviso: stesso contesto di finestra/documento; rischio di conflitti tra script se il frammento contiene <script> tag
Isolato: contesto finestra separato; nessun rischio di collisione
Condiviso: stesso contesto della finestra ma con ambito DOM; gli script all’interno della radice shadow vengono eseguiti nel contesto host
Supporto tra diverse origini
Richiede intestazioni CORS nell’URL di pubblicazione (il servizio le configura)
Funziona in modo nativo: gli iframe caricano contenuti tra origini diverse senza CORS
Richiede intestazioni CORS nell’URL di pubblicazione (come in linea)
Complessità dell’implementazione
Minimo — poche righe di JS
Trivial: è richiesto zero JS; HTML puro
Bassa: circa 20 righe di JS per la definizione di elemento personalizzato, riutilizzabili in tutta la pagina
Ideale per
Prototipi, contenuti attendibili della stessa origine, contesti in cui l’integrazione del layout è fondamentale e i conflitti CSS sono gestibili
Incorporamento rapido, contenuti in sandbox, scenari tra origini diverse in cui CORS non è disponibile, contenuti che devono essere completamente isolati
Utilizzo in produzione: bilancia isolamento, partecipazione al layout e accessibilità (consigliato per i componenti core di AEM e i siti esterni)

Elemento in linea (recupero + innerHTML) inline-element-fetch-and-innerhtml

L’approccio più semplice:

  1. recuperare l’URL di pubblicazione
  2. inserire il HTML in un elemento contenitore

Esempio di incorporamento di un elemento in linea:

<div id="cf-container"></div>
<script>
  fetch("<publish-url>")
    .then(r => r.ok ? r.text() : Promise.reject(r.status))
    .then(html => {
      document.getElementById("cf-container").innerHTML = html;
    })
    .catch(err => console.error("Failed to load fragment", err));
</script>

Quando utilizzare:

  • Creazione rapida di prototipi o pagine di verifica
  • Contesti con la stessa origine in cui si controllano sia gli stili della pagina host che quelli dei frammenti
  • Quando la massima flessibilità del layout è più importante dell’incapsulamento degli stili
CAUTION
Rischio collisione CSS
Gli stili inline del frammento (inclusi i blocchi <style>, le dichiarazioni font-face e i selettori di elementi) si uniscono nella cascata della pagina host.
Questo può causare sostituzioni di stile non desiderate in entrambe le direzioni.
Utilizza questa tecnica solo quando puoi tollerare o gestire attivamente questi conflitti.

iframe iframe

Carica l’URL di pubblicazione direttamente come src di un <iframe>. Non è richiesto alcun JavaScript.

Esempio di incorporamento di iframe:

<iframe
  src="<publish-url>"
  title="Content Fragment Preview"
  width="100%"
  height="600"
  frameborder="0"
  style="border: none;"
></iframe>

È inoltre possibile ridimensionare automaticamente l’iframe (opzionale).

Per ridimensionare dinamicamente l’iframe all’altezza del contenuto (evitando le barre di scorrimento), utilizza un pattern postMessage o una libreria appropriata.

Un esempio di approccio leggero è:

<iframe id="cf-iframe" src="<publish-url>" title="Content Fragment Preview"
  width="100%" frameborder="0" style="border:none; overflow:hidden;"
  onload="this.style.height = this.contentDocument.documentElement.scrollHeight + 'px';"
></iframe>
WARNING
L'approccio di ridimensionamento automatico di onload sopra funziona solo per gli iframe same-origin.
Per gli URL di pubblicazione di cross-origin, è necessaria una soluzione basata su postMessage o per impostare un'altezza fissa.

Quando utilizzare:

  • Blocco di incorporamento Edge Delivery Services (integrazione predefinita — vedi sezione seguente)
  • Contesti in cui l’isolamento completo di CSS/JS è critico
  • Incorporamento tra origini diverse in cui CORS non è configurato
  • Integrazione rapida del codice zero (è sufficiente incollare l’URL)

Definisci un elemento personalizzato <cf-visualization> riutilizzabile che recuperi l’URL di pubblicazione e inserisca il HTML in una radice DOM shadow incapsulata.

Questo elemento fornisce:

  • Isolamento DOM ombra
    • Il markup e gli stili del frammento sono incapsulati in una directory principale shadow, evitando conflitti con la cascata CSS della pagina host.
  • Partecipazione al layout in linea
    • Il contenuto sottoposto a rendering partecipa al flusso normale del documento host, rispondendo al dimensionamento del contenitore e ai contesti flexbox/grid senza la gestione manuale delle dimensioni.
  • Contesto di navigazione singolo
    • Non viene creato alcun contesto di documento secondario; il contenuto del frammento condivide il runtime JavaScript della pagina ed è completamente fruibile dalle tecnologie per l’accessibilità.
  • Sovraccarico minimo
    • Una singola chiamata fetch recupera il HTML pre-renderizzato dal livello di pubblicazione. Non è richiesto alcun framework di rendering lato client.
IMPORTANT
Questo è l’approccio consigliato per l’utilizzo in produzione ed è la tecnica utilizzata dai Componenti core di AEM.

Per definire l’elemento personalizzato, includi il seguente script una volta per pagina. Tutte le <cf-visualization> istanze della pagina utilizzeranno questa definizione:

<script>
  class CfVisualization extends HTMLElement {
    connectedCallback() {
      const src = this.getAttribute("src");
      if (!src) return;

      const shadow = this.attachShadow({ mode: "open" });

      fetch(src)
        .then((r) => (r.ok ? r.text() : Promise.reject(r.status)))
        .then((html) => {
          shadow.innerHTML = html;
        })
        .catch((err) => {
          console.error("cf-visualization: failed to load", src, err);
        });
    }
  }

  if (!customElements.get("cf-visualization")) {
    customElements.define("cf-visualization", CfVisualization);
  }
</script>

Per utilizzare l’elemento personalizzato:

<cf-visualization src="<publish-url>"></cf-visualization>

Quando utilizzare:

  • Pagine AEM Sites che utilizzano i Componenti core (questo è il comportamento integrato)
  • Siti web esterni/di terze parti che richiedono un’integrazione pulita e riutilizzabile
  • Qualsiasi contesto in cui è necessario sia l’isolamento degli stili che la partecipazione al flusso di layout

Integrazione con Edge Delivery Services (blocco di incorporamento) integration-with-edge-services-embed-block

In Edge Delivery Services, l’URL di pubblicazione viene utilizzato tramite un blocco di incorporamento, che lo rende come <iframe>.

  1. Verifica che il blocco di incorporamento esista nel progetto.

    Se il progetto EDS non include già il blocco di incorporamento, copialo dall’archivio di raccolta blocchi aem:

    code language-cmdline
    # From the aem-block-collection repo, copy blocks/embed/ into your project's blocks/ directory
    cp -r aem-block-collection/blocks/embed/ your-eds-project/blocks/embed/
    
  2. Creare l’incorporamento nell’editor di authoring dei documenti (in Edge Delivery Services)

    In Document Authoring, i blocchi sono rappresentati come tabelle. Per aggiungere un’incorporazione di frammenti di contenuto visivo:

    table 0-row-1 1-row-1
    incorporare
    (incolla l’URL di pubblicazione come collegamento ipertestuale)

    In alternativa, se il progetto o Sidekick è configurato con il blocco Incorpora nella relativa libreria di blocchi, puoi inserirlo tramite il menu barra e incollare l’URL di pubblicazione nel contenuto del blocco.

  3. Risultato

    Il blocco di incorporamento esegue il rendering dell’URL di pubblicazione in un <iframe>. Il contenuto del frammento viene caricato in isolamento CSS completo all’interno del layout di pagina EDS.

Integrazione: AEM Sites con i Componenti core integration-aem-sites-with-core-components

Il componente core Frammento di contenuto (core/wcm/components/contentfragment/v1/contentfragment) dispone del supporto integrato per il rendering dei Frammenti di contenuto visivo tramite la tecnica Elemento cliente + DOM shadow.

Come funziona:

  • Modalità Autore:

    Quando displayMode del componente è impostato su vcf, la libreria client di authoring (vcfRenderer.js) recupera il frammento HTML dall’API di anteprima e lo riproduce in linea nell’area di lavoro di authoring.

    Un esempio di endpoint per l’anteprima di authoring è:

    code language-html
    GET /adobe/sites/cf/fragments/{fragmentId}/preview?templateId={templateId}&variation={variation}
    
  • Modalità di pubblicazione:

    Nella pagina pubblicata (wcmmode.disabled), il modello HTL esegue il rendering di uno script in linea che recupera dall’URL di pubblicazione e inserisce il HTML in una radice DOM shadow.

    Esempio di frammento di contenuto visivo del componente core (templates.html):

    code language-html
    <div class="cmp-contentfragment cmp-contentfragment--vcf"
       data-cmp-contentfragment-id="{fragmentId}"
       data-cmp-contentfragment-vcf-template="{templateId}"
       data-cmp-contentfragment-variation="{variation}">
      <!-- Only rendered when wcmmode.disabled (publish) -->
      <div data-vcf-url="{vcfPublishUrl}" class="cmp-contentfragment__vcf-loader" style="display:none"></div>
      <script>
          (function() {
              var script = document.currentScript;
              var loader = script.previousElementSibling;
              var el = script.parentElement;
              if (!el || !loader) return;
              var url = loader.dataset.vcfUrl;
              if (!url) return;
              loader.remove();
              var shadow = el.attachShadow({ mode: "open" });
              var body = document.createElement("body");
              body.style.display = "none";
              shadow.appendChild(body);
              fetch(url)
                  .then(function(r) { return r.ok ? r.text() : Promise.reject(r.status); })
                  .then(function(html) {
                      body.innerHTML = html;
                      body.style.display = "";
                  });
          })();
      </script>
    </div>
    

    Formato URL di pubblicazione:

    Il modello Sling (ContentFragmentImpl) crea l’URL di pubblicazione utilizzando il seguente pattern:

    code language-html
    /adobe/experimental/previewtemplates-expires-20260301/contentFragments/{templateId}/{fragmentId}/{variation}.html
    

    Questo URL relativo viene risolto rispetto all’host di pubblicazione in fase di esecuzione.

Integrazione con siti esterni integration-with-external-sites

Per i siti Web non AEM, utilizzare la tecnica Elemento cliente + DOM ombra. In questo modo è possibile ottenere un’integrazione dichiarativa senza dipendenze del framework.

Un esempio è:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Product Page</title>
</head>
<body>
  <h1>Product Details</h1>
  <p>Some host-page content here...</p>

  <!-- Embed the Content Fragment visualization -->
  <cf-visualization
    src="https://publish-p12345-e67890.adobeaemcloud.com/adobe/experimental/previewtemplates-expires-20260301/contentFragments/product_template/abc-123/master.html"
  ></cf-visualization>

  <p>More host-page content below the fragment...</p>

  <!-- Custom Element definition (include once) -->
  <script>
    class CfVisualization extends HTMLElement {
      connectedCallback() {
        const src = this.getAttribute("src");
        if (!src) return;
        const shadow = this.attachShadow({ mode: "open" });
        fetch(src)
          .then(r => r.ok ? r.text() : Promise.reject(r.status))
          .then(html => { shadow.innerHTML = html; })
          .catch(err => console.error("cf-visualization: failed to load", src, err));
      }
    }
    if (!customElements.get("cf-visualization")) {
      customElements.define("cf-visualization", CfVisualization);
    }
  </script>
</body>
</html>
NOTE
È possibile inserire più elementi <cf-visualization> nella stessa pagina con src URL diversi. La definizione dell’elemento personalizzato deve essere inclusa una sola volta.

CORS e considerazioni sulla sicurezza cors-and-security-considerations

Preoccupazione
Dettagli
CORS
Il servizio di visualizzazione dei frammenti di contenuto configura CORS nel percorso /adobe/** con origini consentite configurabili.
L’elemento in linea Fetch + innerHTML 1 e le tecniche Elemento cliente + DOM shadow (che utilizzano fetch()) richiedono che l’origine della pagina host sia nell’elenco Consentiti.
La tecnica iFrame non richiede CORS.
CSP/X-Frame-Options
Il servizio non imposta le intestazioni Content-Security-Policy o X-Frame-Options sul HTML pubblicato. Se la rete CDN o Dispatcher aggiunge queste intestazioni, verifica che consentano l’accesso ai frame (per iFrame) o fetch() (per DOM in linea/ombra) dalle origini host.
Attendibilità contenuto
Il HTML pubblicato viene sottoposto a pre-rendering dai dati dei frammenti di contenuto creati utilizzando modelli Handlebars gestiti dal servizio. Non include script generati dall’utente. Tuttavia, come per qualsiasi iniezione innerHTML, assicurati di considerare attendibile l’origine sorgente.

Scegliere la tecnica appropriata choose-the-appropriate-technique

Utilizza quanto segue come guida alle decisioni per aiutarti a scegliere la tecnica appropriata:

Scenario
Soluzione
È necessario azzerare il JavaScript e l’isolamento completo?
Iframe
Hai bisogno della partecipazione al flusso di layout con l’isolamento dello stile?
Elemento personalizzato + DOM ombra (consigliato)
Hai bisogno di prototipi più veloci, la stessa origine e i conflitti CSS sono accettabili?
Elemento in linea
Incorporare in Edge Delivery Services?
Blocco da incorporare (iframe sotto il cofano)
Incorporare nelle pagine AEM Sites?
Componente core (Shadow DOM, integrato)
recommendation-more-help
experience-manager-cloud-service-help-main-toc