App Next.js

[AEM headless as a Cloud Service]{class="badge informative"}

Le applicazioni di esempio sono un ottimo modo per esplorare le funzionalità headless di Adobe Experience Manager (AEM). Questa applicazione Next.js illustra come eseguire query sui contenuti che utilizzano le API GraphQL dell’AEM utilizzando query persistenti. Il client headless AEM per JavaScript viene utilizzato per eseguire le query persistenti GraphQL che alimentano l’app.

App Next.js con AEM headless

Visualizza il codice sorgente in GitHub

Prerequisiti prerequisites

I seguenti strumenti devono essere installati localmente:

Requisiti AEM

L’app Next.js funziona con le seguenti opzioni di distribuzione AEM. Tutte le distribuzioni richiedono l'installazione di Sito WKND condiviso v3.0.0+ o Sito WKND v3.0.0+ nell'ambiente AEM as a Cloud Service.

L'app Next.js di questo esempio è progettata per connettersi al servizio AEM Publish.

Requisiti dell’autore AEM

Next.js è progettato per connettersi al servizio AEM Publish e accedere a contenuto non protetto. Il file Next.js può essere configurato per la connessione all'istanza di creazione AEM tramite le proprietà .env descritte di seguito. Le immagini trasmesse da AEM Author richiedono l’autenticazione, pertanto anche l’utente che accede all’app Next.js deve essere registrato in AEM Author.

Come usare

  1. Clona l'archivio adobe/aem-guides-wknd-graphql:

    code language-shell
    $ git clone git@github.com:adobe/aem-guides-wknd-graphql.git
    
  2. Modificare il file aem-guides-wknd-graphql/next-js/.env.local e impostare NEXT_PUBLIC_AEM_HOST sul servizio AEM.

    code language-plain
    # AEM service
    NEXT_PUBLIC_AEM_HOST=https://publish-p123-e456.adobeaemcloud.com/
    ...
    

    Se ci si connette al servizio di authoring AEM, è necessario fornire l’autenticazione in quanto il servizio di authoring AEM è protetto per impostazione predefinita.

    Per utilizzare un set di account AEM locale AEM_AUTH_METHOD=basic e fornire il nome utente e la password nelle proprietà AEM_AUTH_USER e AEM_AUTH_PASSWORD.

    code language-plain
    ...
    # The variables are not prefixed with NEXT_PUBLIC so they are only available server-side
    AEM_AUTH_METHOD=basic
    AEM_AUTH_USER=aem-user-account
    AEM_AUTH_PASSWORD=password-for-the-aem-user-account
    

    Per utilizzare un token di sviluppo locale AEM as a Cloud Service, impostare AEM_AUTH_METHOD=dev-token e fornire il valore del token di sviluppo completo nella proprietà AEM_AUTH_DEV_TOKEN.

    code language-plain
    ...
    # The variables are not prefixed with NEXT_PUBLIC so they are only available server-side
    AEM_AUTH_METHOD=dev-token
    AEM_AUTH_DEV_TOKEN=my-dev-token
    
  3. Modificare il file aem-guides-wknd-graphql/next-js/.env.local e convalidare NEXT_PUBLIC_AEM_GRAPHQL_ENDPOINT è impostato sull'endpoint GraphQL AEM appropriato.

    Quando si utilizza Sito WKND condiviso o Sito WKND, utilizzare l'endpoint API di GraphQL wknd-shared.

    code language-plain
    ...
    NEXT_PUBLIC_AEM_GRAPHQL_ENDPOINT=wknd-shared
    ...
    
  4. Apri un prompt dei comandi e avvia l’app Next.js utilizzando i seguenti comandi:

    code language-shell
    $ cd aem-guides-wknd-graphql/next-js
    $ npm install
    $ npm run dev
    
  5. Una nuova finestra del browser apre l'app Next.js in http://localhost:3000

  6. L’app Next.js mostra un elenco di avventure. Quando si seleziona un’avventura, i relativi dettagli vengono aperti in una nuova pagina.

Il codice

Di seguito è riportato un riepilogo di come viene creata l’app Next.js, di come si connette a AEM Headless per recuperare contenuti utilizzando query persistenti di GraphQL e di come vengono presentati i dati. Il codice completo si trova su GitHub.

Query persistenti

Seguendo le best practice di AEM Headless, l’app Next.js utilizza query persistenti di AEM GraphQL per eseguire query sui dati dell’avventura. L’app utilizza due query persistenti:

  • Query persistente wknd/adventures-all, che restituisce tutte le avventure in AEM con un set abbreviato di proprietà. Questa query persistente guida l’elenco di avventure della visualizzazione iniziale.
# Retrieves a list of all Adventures
#
# Optional query variables:
# - { "offset": 10 }
# - { "limit": 5 }
# - {
#    "imageFormat": "JPG",
#    "imageWidth": 1600,
#    "imageQuality": 90
#   }
query ($offset: Int, $limit: Int, $sort: String, $imageFormat: AssetTransformFormat=JPG, $imageWidth: Int=1200, $imageQuality: Int=80) {
  adventureList(
    offset: $offset
    limit: $limit
    sort: $sort
    _assetTransform: {
      format: $imageFormat
      width: $imageWidth
      quality: $imageQuality
      preferWebp: true
  }) {
    items {
      _path
      slug
      title
      activity
      price
      tripLength
      primaryImage {
        ... on ImageRef {
          _path
          _dynamicUrl
        }
      }
    }
  }
}
  • Query persistente wknd/adventure-by-slug, che restituisce una singola avventura di slug (una proprietà personalizzata che identifica in modo univoco un'avventura) con un set completo di proprietà. Questa query persistente attiva le visualizzazioni dei dettagli dell’avventura.
# Retrieves an Adventure Fragment based on it's unique slug.
#
# Required query variables:
# - {"slug": "bali-surf-camp"}
#
# Optional query variables:
# - {
#     "imageFormat": "JPG",
#     "imageSeoName": "my-adventure",
#     "imageWidth": 1600,
#     "imageQuality": 90
#   }
#
# This query returns an adventure list but since the the slug property is set to be unique in the Content Fragment Model, only a single Content Fragment is expected.

query ($slug: String!, $imageFormat:AssetTransformFormat=JPG, $imageSeoName: String, $imageWidth: Int=1200, $imageQuality: Int=80) {
  adventureList(
    filter: {slug: {_expressions: [{value: $slug}]}}
    _assetTransform: {
      format: $imageFormat
      seoName: $imageSeoName
      width: $imageWidth
      quality: $imageQuality
      preferWebp: true
  }) {
    items {
      _path
      title
      slug
      activity
      adventureType
      price
      tripLength
      groupSize
      difficulty
      price
      primaryImage {
        ... on ImageRef {
          _path
          _dynamicUrl
        }
      }
      description {
        json
        plaintext
        html
      }
      itinerary {
        json
        plaintext
        html
      }
    }
    _references {
      ... on AdventureModel {
        _path
        slug
        title
        price
        __typename
      }
    }
  }
}

Esegui query persistente GraphQL

Le query persistenti dell'AEM vengono eseguite su HTTP GET, pertanto il client AEM Headless per JavaScript viene utilizzato per eseguire le query GraphQL persistenti sull'AEM e caricare il contenuto dell'avventura nell'app.

Ogni query persistente ha una funzione corrispondente in src/lib//aem-headless-client.js, che chiama l'endpoint GraphQL dell'AEM e restituisce i dati dell'avventura.

Ogni funzione a sua volta richiama aemHeadlessClient.runPersistedQuery(...), eseguendo la query GraphQL persistente.

// src/lib/aem-headless-client.js

...
/**
 * Invokes the 'adventures-all` persisted query using the parameterizable namespace.
 *
 * @returns a GraphQL response of all adventures.
 */
async getAllAdventures() {
  const queryAdventuresAll = process.env.NEXT_PUBLIC_AEM_GRAPHQL_ENDPOINT + '/adventures-all';

  try {
    return await this.aemHeadlessClient.runPersistedQuery(queryAdventuresAll);
  } catch(e) {
    console.error(e)
  }
}

// And so on, and so forth ...

async getAdventureSlugs(queryVariables) { ... }

async getAdventuresBySlug(slug, queryVariables) { ... }
...

Pagine

L’app Next.js utilizza due pagine per presentare i dati dell’avventura.

  • src/pages/index.js

    Utilizza getServerSideProps() 🔗 di Next.js per chiamare getAllAdventures() e visualizza ogni avventura come una scheda.

    L'utilizzo di getServerSiteProps() consente il rendering lato server della pagina Next.js.

  • src/pages/adventures/[...slug].js

    Percorso dinamico Next.js che visualizza i dettagli di una singola avventura. Questa route dinamica preacquisisce i dati di ogni avventura utilizzando getStaticProps() 🔗 di Next.js tramite una chiamata a getAdventureBySlug(slug, queryVariables) tramite il parametro slug trasmesso tramite la selezione dell'avventura nella pagina adventures/index.js e queryVariables per controllare il formato, la larghezza e la qualità dell'immagine.

    La route dinamica è in grado di prerecuperare i dettagli per tutte le avventure utilizzando GetStaticPaths() di Next.js e popolando tutte le permutazioni di route possibili in base all'elenco completo delle avventure restituite dalla query GraphQL getAdventurePaths()

    L'utilizzo di getStaticPaths() e getStaticProps(..) ha consentito la generazione statica del sito di queste pagine Next.js.

Configurazione della distribuzione

Le app Next.js, soprattutto nel contesto del rendering lato server (SSR) e della generazione lato server (SSG), non richiedono configurazioni di sicurezza avanzate come la condivisione delle risorse tra le origini (CORS).

Tuttavia, se Next.js effettua richieste HTTP all’AEM dal contesto del client, potrebbero essere necessarie configurazioni di sicurezza nell’AEM. Per ulteriori dettagli, consulta l'esercitazione sulla distribuzione di app headless a pagina singola AEM.

recommendation-more-help
e25b6834-e87f-4ff3-ba56-4cd16cdfdec4