Blog in Next.js mit Headless Oracle Content Management erstellen

Einführung

Next.js ist ein Open-Source-Web-Front-End-Entwicklungs-Framework für React, das Funktionen wie serverseitiges Rendering ermöglicht und statische Websites für React-basierte Webanwendungen generiert. Aber was geschieht, wenn Sie ein Content Management System (CMS) benötigen, um all Ihre Inhalte zu bedienen? Glücklicherweise bietet Oracle Content Management mit seinen umfassenden Headless-CMS-Funktionen eine anständige Lösung für Ihre Anforderungen an Inhaltsadministration und Governance.

In diesem Tutorial erstellen wir einen einfachen Blog in Next.js, indem wir Oracle Content Management als Headless CMS sowie sein Software Development Kit (SDK) für die Inhaltsbereitstellung in JavaScript nutzen. Dieses Next.js-Beispiel ist auf GitHub verfügbar.

Das Tutorial besteht aus drei Aufgaben:

  1. Oracle Content Management vorbereiten
  2. Blog in Next.js erstellen
  3. Vorbereitung der Anwendung auf das Deployment

Voraussetzungen

Bevor Sie mit diesem Tutorial fortfahren, sollten Sie zuerst die folgenden Informationen lesen:

Um diesem Tutorial zu folgen, benötigen Sie:

Was wir bauen

Unser Blog besteht aus einer dreiseitigen Website, auf der Besucher Blogartikel in Themen kennenlernen können. Die erste Seite, die Homepage, besteht aus Branding (Firmenname und Logo), einigen Links und einer Liste von Blog-Themen.

Im Folgenden finden Sie den Endstatus unseres Tutorials, einem grundlegenden Blog von Next.js, der Inhalte aus Oracle Content Management verbraucht:

https://headless.mycontentdemo.com/samples/oce-nextjs-blog-sample

Die Homepage sieht am Ende dieses Tutorials aus:

Diese Abbildung zeigt die Homepage für die Cafe Supremo-Demosite mit einer Liste der verfügbaren Themen.

Auf der zweiten Seite, der Themenseite, werden Vorschauen für jeden Blogartikel angezeigt, der zum Thema gehört. So sieht eine einzelne Themenseite aus:

Diese Abbildung zeigt eine Themenseite mit dem Namen "Rezepte" mit einer Liste der verfügbaren Artikel für dieses Thema.

Schließlich gibt die Artikelseite den letzten Blogartikel wieder, einschließlich Informationen zum Autor des Blogs. So sieht eine einzelne Artikelseite aus:

Diese Abbildung zeigt eine einzelne Artikelseite mit Inhalt und Autorreferenz.

Um fortzufahren, benötigen Sie ein aktives Abonnement für Oracle Content Management und müssen mit der Rolle "Content Administrator" angemeldet sein.

Aufgabe 1: Oracle Content Management vorbereiten

Wenn noch keine Oracle Content Management-Instanz vorhanden ist, erfahren Sie unter Schnellstart, wie Sie sich für Oracle Cloud registrieren, eine Oracle Content Management-Instanz bereitstellen und Oracle Content Management als Headless CMS konfigurieren.

Für dieses Tutorial benötigen Sie zwei Möglichkeiten, um ein Contentmodell zu erstellen. Es ist ein herunterladbares Assetpaket verfügbar, das Ihr leeres Repository mit Inhaltstypen und zugehörigen Inhalten ausfüllt, oder Sie können Ihr eigenes Contentmodell und Ihren eigenen Inhalt erstellen.

So bereiten Sie Oracle Content Management vor:

  1. Erstellen Sie einen Kanal und ein Asset-Repository.
  2. Inhaltsmodell erstellen mit einer der beiden folgenden Methoden:

Kanal- und Asset-Repository erstellen

Sie müssen zuerst einen Kanal und ein Asset-Repository in Oracle Content Management erstellen, damit Sie Inhalte veröffentlichen können.

So erstellen Sie einen Kanal und ein Asset-Repository in Oracle Content Management:

  1. Melden Sie sich als Administrator bei der Oracle Content Management-Webbenutzeroberfläche an.

  2. Wählen Sie im linken Navigationsmenü die Option Inhalt und anschließend Kanäle veröffentlichen aus der Auswahlliste im Seitenheader.

    Diese Abbildung zeigt die Option "Veröffentlichungskanäle veröffentlichen", die im Dropdown-Menü im Header der Seite "Inhalt" ausgewählt wurde.

  3. Klicken Sie in der oberen rechten Ecke auf Erstellen, um einen neuen Kanal zu erstellen. Benennen Sie den Kanal "OCEGettingStartedChannel" für die Zwecke dieses Tutorials, und behalten Sie den Zugriff öffentlich. Klicken Sie auf Speichern, um den Kanal zu erstellen.

    Diese Abbildung zeigt den Bereich "Veröffentlichungskanaldefinition" mit "OCEGettingStartedChannel" im Feld "Kanalname".

  4. Wählen Sie Inhalt im linken Navigationsmenü, und wählen Sie Repositorys aus der Auswahlliste im Seitenheader aus.

    Diese Abbildung zeigt die Option "Repositorys", die im Dropdown-Menü im Header der Seite "Inhalt" ausgewählt wurde.

  5. Klicken Sie in der oberen rechten Ecke auf Erstellen, um ein neues Asset-Repository zu erstellen. Benennen Sie das Asset-Repository "OCEGettingStartedRepository" für die Zwecke dieses Tutorials.

    Diese Abbildung zeigt den Bereich "Repository-Definition" mit "OCEGettingStartedRepository" im Feld "Repository-Name".

  6. Wählen Sie im Feld Veröffentlichungskanäle den Kanal OCEGettingStartedChannel aus, um Oracle Content Management anzugeben, dass Inhalte im Repository OCEGettingStartedRepository im Kanal OCEGettingStartedChannel veröffentlicht werden können. Klicken Sie abschließend auf Speichern.

    Diese Abbildung zeigt den Bereich "Repository-Definition" mit "OCEGettingStartedChannel" im Feld "Veröffentlichungskanäle".

Contentmodelle erstellen

Als nächste Aufgabe wird ein Contentmodell erstellt. Sie haben zwei Möglichkeiten:

Oracle Content Management Samples Asset Pack importieren

Sie können ein vorkonfiguriertes Oracle Content Management-Beispielassetspaket herunterladen, das alle erforderlichen Inhaltstypen und -assets für dieses Tutorial enthält. Gegebenenfalls können Sie auch ein eigenes Contentmodell erstellen, anstatt das Beispielassetspaket herunterzuladen.

Sie können eine Kopie des Inhalts, den wir in diesem Tutorial verwenden, aus dem Oracle Content Management Samples Asset Pack hochladen. Dadurch können Sie mit den Inhaltstypen experimentieren und den Inhalt ändern. Wenn Sie das Oracle Content Management Samples Asset Pack importieren möchten, können Sie das Assetpack-Archiv, OCESamplesAssetPack.zip, herunterladen und in ein Verzeichnis Ihrer Wahl extrahieren:

  1. Laden Sie das Oracle Content Management Samples Asset Pack (OCESamplesAssetPack.zip) von der Seite Downloads von Oracle Content Management herunter. Extrahieren Sie die heruntergeladene ZIP-Datei an einen Speicherort auf Ihrem Computer. Nach der Extraktion enthält dieser Speicherort eine Datei namens OCEGettingStarted_data.zip.

  2. Melden Sie sich als Administrator bei der Oracle Content Management-Webbenutzeroberfläche an.

  3. Wählen Sie Inhalt im linken Navigationsmenü, und wählen Sie Repositorys aus der Auswahlliste im Seitenheader aus. Wählen Sie jetzt OCEGettingStartedRepository, und klicken Sie in der oberen Aktionsleiste auf die Schaltfläche Inhalt importieren.

    Diese Abbildung zeigt die Seite "Repositorys", wobei das Element OCEGettingStartedRepository ausgewählt ist.

  4. Laden Sie OCEGettingStarted_data.zip von Ihrem lokalen Computer in den Ordner Dokumente hoch.

    Diese Abbildung zeigt den Bildschirm zur Uploadbestätigung für die OCEGettingStarted_data.zip-Datei.

  5. Wählen Sie nach dem Hochladen OCEGettingStarted_data.zip aus, und klicken Sie auf OK, um den Inhalt in das Asset-Repository zu importieren.

    Diese Abbildung zeigt die ausgewählte OCEGettingStarted_data.zip-Datei mit aktivierter Schaltfläche "OK".

  6. Nachdem der Inhalt erfolgreich importiert wurde, navigieren Sie zur Seite Anlagen, und öffnen Sie das Repository OCEGettingStartedRepository. Sie sehen, dass alle zugehörigen Bilder und Inhaltselemente jetzt dem Asset-Repository hinzugefügt wurden.

    Diese Abbildung zeigt das OCEGettingStartedRepository-Repository mit allen Assets, die gerade importiert wurden.

  7. Klicken Sie oben links auf Alle auswählen und dann auf Veröffentlichen, um alle importierten Assets dem Veröffentlichungskanal hinzuzufügen, den Sie zuvor erstellt haben: OCEGettingStartedChannel.

    Diese Abbildung zeigt das Repository OCEGettingStartedRepository mit allen ausgewählten Assets und der Option "Veröffentlichen" in der Aktionsleiste.

  8. Vor der Veröffentlichung müssen Sie alle Anlagen validieren. Fügen Sie zuerst OCEGettingStartedChannel als ausgewählten Kanal hinzu, und klicken Sie auf die Schaltfläche Validieren.

    Diese Abbildung zeigt die Seite "Validierungsergebnisse", auf der der Kanal OCEGettingStartedChannel im Feld "Kanäle" hinzugefügt wurde, alle zu validierenden Assets und die Schaltfläche "Validieren" aktiviert sind.

  9. Nachdem die Assets validiert wurden, können Sie alle Assets im ausgewählten Kanal veröffentlichen, indem Sie oben rechts auf die Schaltfläche Veröffentlichen klicken.

    Diese Abbildung zeigt die Seite "Validierungsergebnisse", auf der der Kanal OCEGettingStartedChannel im Feld "Kanäle" hinzugefügt, alle Assets validiert und die Schaltfläche "Veröffentlichen" aktiviert ist.

Anschließend können Sie auf der Seite Anlagen sehen, dass alle Assets veröffentlicht wurden. (Sie können das Symbol über dem Assetnamen erkennen.)

Diese Abbildung zeigt die Seite "Anlagen" mit allen Assets.

Nach dem Import des Oracle Content Management Samples Asset Pack können Sie den Blog in Next.js erstellen.

Eigenes Contentmodell erstellen

Anstatt das Oracle Content Management Samples Asset Pack zu importieren, können Sie auch Ihr eigenes Contentmodell erstellen.

Für dieses Tutorial verwenden wir den Inhaltstyp "OCEGettingStartedHomePage", um die Homepage für unseren Blog zu erstellen. Diese Homepage besteht aus Branding (Firmenname und Logo), einigen URLs für Links und einer Liste der Blog-Themen, die auf der Seite enthalten sein sollten.

Diese Abbildung zeigt die Homepage für die Cafe Supremo-Demosite.

So erstellen Sie Inhaltstypen für das Contentmodell:

  1. Melden Sie sich als Administrator bei der Oracle Content Management-Webbenutzeroberfläche an.
  2. Wählen Sie im linken Navigationsmenü die Option Inhalt und anschließend Anlagentypen aus der Auswahlliste im Seitenheader.
  3. Klicken Sie auf Erstellen in der oberen rechten Ecke.
  4. Wählen Sie diese Option, um einen Inhaltstyp zu erstellen (kein digitaler Assettyp). Wiederholen Sie diesen Vorgang für alle erforderlichen Inhaltstypen.

Diese Abbildung zeigt das Dialogfeld "Anlagentyp erstellen" in der Webbenutzeroberfläche von Oracle Content Management.

Wir erstellen vier Inhaltstypen mit jeweils eigenen Feldern:

Der erste Inhaltstyp, OCEGettingStartedHomePage, sollte folgende Felder enthalten:

Anzeigename Feldtyp erforderlich Rechnername
Unternehmensname Einzelwert-Textfeld X company_name
Firmenlogo Einzelwert-Textfeld X company_logo
Themen Referenzfeld mit mehreren Werten X Themen
Kontakt-URL Einzelwert-Textfeld X contact_url
Info URL Einzelwert-Textfeld X about_url

Die OCEGettingStartedHomePage-Inhaltstypdefinition sollte wie folgt aussehen:

Diese Abbildung zeigt die Definition für den Inhaltstyp "OCEGettingStartedHomePage". Sie enthält folgende Datenfelder: Firmenname, Unternehmenslogo, Themen, Kontakt-URL und Info-URL.

Der zweite Inhaltstyp OCEGettingStartedTopic muss folgendes Feld enthalten:

Anzeigename Feldtyp erforderlich Rechnername
Thumbnail Bildfeld mit einem Wert X Thumbnail

Der Inhaltstyp OCEGettingStartedTopic sollte wie folgt aussehen:

Diese Abbildung zeigt die Definition für den Inhaltstyp "OCEGettingStartedTopic". Er enthält dieses Datenfeld: Miniaturbild.

Der dritte Inhaltstyp OCEGettingStartedAuthor sollte folgende Felder enthalten:

Anzeigename Feldtyp erforderlich Rechnername
Avatar Bildfeld mit einem Wert X Avatar

Der Inhaltstyp OCEGettingStartedAuthor sollte wie folgt aussehen:

Diese Abbildung zeigt die Definition für den Inhaltstyp "OCEGettingStartedAuthor". Es enthält dieses Datenfeld: Avatar.

Der vierte und letzte Inhaltstyp OCEGettingStartedArticle sollte folgende Felder enthalten:

Anzeigename Feldtyp erforderlich Rechnername
Veröffentlichungsdatum Feld mit einem Wert X published_name
Autor Referenzfeld mit einem Wert X Autor
Bild Bildfeld mit einem Wert X Image
Bildunterschrift Einzelwert-Textfeld X image_caption
Artikelinhalt Großtextfeld mit einem Wert X article_content
Thema Referenzfeld mit einem Wert X Thema

Der Inhaltstyp OCEGettingStartedArticle sollte wie folgt aussehen:

Diese Abbildung zeigt die Definition für den Inhaltstyp "OCEGettingStartedArticlePage". Sie enthält folgende Datenfelder: Veröffentlichungsdatum, Autor, Bild, Bildbeschriftung, Artikelinhalt und Thema.

Nachdem Sie Ihre Inhaltstypen erstellt haben, können Sie diese Inhaltstypen dem zuvor erstellten Repository OCEGettingStartedRepository hinzufügen:

  1. Melden Sie sich als Administrator bei der Oracle Content Management-Webbenutzeroberfläche an.
  2. Navigieren Sie zu OCEGettingStartedRepository.
  3. Bearbeiten Sie das Repository, und geben Sie unter Anlagentypen alle vier neu erstellten Inhaltstypen an. Klicken Sie auf Speichern, um die Änderungen zu speichern.

Diese Abbildung zeigt die Seite "Repository bearbeiten" in Oracle Content Management mit den vier neu erstellten Inhaltstypen, die mit dem Repository OCEGettingStartedRepository verknüpft sind.

Nachdem Sie die Inhaltstypen zum Repository hinzugefügt haben, können Sie das Repository OCEGettingStartedRepository auf der Seite Anlagen öffnen und Ihre Inhaltselemente für alle Inhaltstypen erstellen.

Diese Abbildung zeigt Inhaltselemente auf der Seite "Anlagen" in der Oracle Content Management-Webbenutzeroberfläche mit Optionen auf der linken Seite für Collections, Kanäle, Sprachen, Typen, Auswahl von Inhaltselementen und Status.

Aufgabe 2: Blog in Next.js erstellen

Um unsere Oracle Content Management-Inhalte in einer serverseitigen wiedergegebenen Next.js-Anwendung zu verbrauchen, können wir das Next.js-Blogbeispiel verwenden, das als Open-Source-Repository auf GitHub verfügbar ist.

Hinweis: Beachten Sie, dass die Verwendung des Beispiels "Next.js" optional ist. In diesem Tutorial erhalten Sie einen schnellen Einstieg. Sie können auch Ihre eigene Next.js-Anwendung erstellen.

So erstellen Sie den Blog in Next.js:

  1. Beispiel-Repository klonen und Abhängigkeiten installieren
  2. Next.js-Anwendung konfigurieren
  3. Mit dem Oracle Content Management Content-SDK arbeiten
  4. Content-SDK zum Abrufen von Inhalt verwenden

Beispiel-Repository klonen und Abhängigkeiten installieren

Das Next.js-Blogbeispiel ist als Open-Source-Repository in GitHub verfügbar.

Zunächst müssen Sie das Beispiel von GitHub auf Ihren lokalen Computer klonen und Ihr Verzeichnis in das Repository-Root ändern:

git clone https://github.com/oracle/oce-nextjs-blog-sample.git
    cd oce-nextjs-blog-sample

Nachdem Sie jetzt über Ihre Codebasis verfügen, müssen Sie Abhängigkeiten für die Anwendung herunterladen. Führen Sie den folgenden Befehl aus dem Root-Verzeichnis aus:

npm install

Next.js-Anwendung konfigurieren

In diesem Next.js-Blogbeispiel müssen Sie einige Informationen konfigurieren, damit Ihr Oracle Content Management Content-SDK (und andere Anforderungen) die richtige Instanz-URL und API-Version mit dem richtigen Kanaltoken ansprechen kann. Diese Werte werden in script/server-config-utils.js verwendet, um einen neuen Zustellungsclient zu instanziieren.

Diese Anwendung verwendet eine .env.local-Datei, die von Next.js gelesen und dem Code innerhalb der Anwendung mit process.env zur Verfügung gestellt wird.

Öffnen Sie die .env.local-Datei in einem Texteditor. Folgende Informationen werden angezeigt:

# The connection details for the Oracle Content Management server to be used for this application
    SERVER_URL=https://samples.mycontentdemo.com
    API_VERSION=v1.1
    CHANNEL_TOKEN=47c9fb78774d4485bc7090bf7b955632

Ändern Sie die einzelnen Schlüssel/Wert-Paare entsprechend Ihrer Instanz-URL, der gewünschten API-Version und dem mit Ihrem Veröffentlichungskanal verknüpften Kanaltoken. Der Kanal für dieses Tutorial ist OCEGettingStartedChannel.

Mit dem Oracle Content Management Content-SDK arbeiten

Oracle Content Management bietet ein SDK, mit dem Sie Inhalte in Ihren Anwendungen erkennen und verwenden können. Das SDK wird als NPM-Modul veröffentlicht und das Projekt wird auf GitHub gehostet.

Weitere Informationen zum SDK finden Sie hier.

Das SDK wurde als Laufzeitabhängigkeit dieses Projekts in der Datei package.json registriert.

Content-SDK zum Abrufen von Inhalt verwenden

Wir können das Content-SDK jetzt nutzen, um Inhalte abzurufen, damit wir es in unserer Next.js-Anwendung wiedergeben können.

Der Skriptordner enthält den Code zum Abrufen von Daten aus Oracle Content Management mit dem Content-SDK.

Die Datei script/server-config-utils.js importiert das Content SDK und erstellt dann einen Zustellungsclient mit der in .env.local angegebenen Konfiguration.

Der folgende Befehl importiert das SDK:

import { createDeliveryClient, createPreviewClient } from '@oracle/content-management-sdk';

Mit dem folgenden Befehl wird der Delivery Client erstellt:

return createDeliveryClient(serverconfig);

Die Datei script/services.js enthält den gesamten Code zum Abrufen von Daten für die Anwendung. Für jede Seitenkomponente in der Anwendung gibt es eine Hauptfunktion, um alle Daten für diese Seite abzurufen.

Für die Wiedergabe der Images stellt services.js eine Helper-Methode bereit, mit der das Quellset für eine Anlage abgerufen wird, die aus den Wiedergaben für die Anlage erstellt wurde.

function getSourceSet(asset) {
      const urls = {};
      urls.srcset = '';
      urls.jpgSrcset = '';
      if (asset.fields && asset.fields.renditions) {
        asset.fields.renditions.forEach((rendition) => {
          addRendition(urls, rendition, 'jpg');
          addRendition(urls, rendition, 'webp');
        });
      }
      // add the native rendition to the srcset as well
      urls.srcset += `${asset.fields.native.links[0].href} ${asset.fields.metadata.width}w`;
      urls.native = asset.fields.native.links[0].href;
      urls.width = asset.fields.metadata.width;
      urls.height = asset.fields.metadata.height;
      return urls;
    }

Homepage-Daten

Für die Homepage sind mehrere Datenaufrufe erforderlich, um alle Daten abzurufen:

  1. Zuerst fragen wir nach Elementen im Kanal ab, der in .env.local angegeben ist.
  2. Für jedes Thema werden die Details abgerufen.

Öffnen Sie script/services.js, und suchen Sie die Funktion getTopicsListPageData(), die alle Daten für die Homepage abruft.

export function getTopicsListPageData() {
      const client = getDeliveryClient();
      return fetchHomePage(client)
        .then((data) => (
          getRenditionURLs(client, data.logoID)
            .then((renditionUrls) => {
              data.companyThumbnailRenditionUrls = renditionUrls;
              return data;
            })
        ));
    }

Die Funktion fetchHomePage(), die von der Funktion getTopicsListPageData() aufgerufen wird, ruft alle Elemente im Kanal ab. Dadurch werden die Logo-ID, der Firmenname, die Informations- und Kontakt-URLs und eine Themenliste abgerufen.

function fetchHomePage(client) {
      return client.queryItems({
        q: '(type eq "OCEGettingStartedHomePage" AND name eq "HomePage")',
      }).then((data) => {
        const logoID = data.items[0].fields.company_logo.id;
        const title = data.items[0].fields.company_name;
        const aboutUrl = data.items[0].fields.about_url;
        const contactUrl = data.items[0].fields.contact_url;
    
        const { topics } = data.items[0].fields;
        const promises = [];
    
        topics.forEach((origTopic) => {
          // add a promise to the total list of promises to get the full topic details
          promises.push(
            fetchTopic(client, origTopic.id)
              .then((topic) => topic),
          );
        });
    
        // execute all the promises returning a single dimension array of all
        // of the topics and the other home page data
        return Promise.all(promises)
          .then((allTopics) => (
            {
              logoID,
              companyTitle: title,
              aboutUrl,
              contactUrl,
              topics: flattenArray(allTopics),
            }
          )).catch((error) => logError('Fetching topics failed', error));
      }).catch((error) => logError('Fetching home page data failed', error));
    }

Die Funktion fetchTopic() wird dann für jede Themen-ID aufgerufen, um die vollständigen Themendetails abzurufen.

function fetchTopic(client, topicId) {
      return client.getItem({
        id: topicId,
        expand: 'fields.thumbnail',
      }).then((topic) => {
        topic.renditionUrls = getSourceSet(topic.fields.thumbnail);
        return topic;
      }).catch((error) => logError('Fetching topic failed', error));
    }

getTopicsListPageData() ruft auch getRenditionURLs() auf, um die URL des wiederzugebenden Bildes abzurufen.

function getRenditionURLs(client, identifier) {
      return client.getItem({
        id: identifier,
        expand: 'fields.renditions',
      }).then((asset) => getSourceSet(asset))
        .catch((error) => logError('Fetching Rendition URLs failed', error));
    }

Themenseitendaten

Next.js verwendet die statische Sitegenerierung, um jede Seite in der Anwendung vorab wiederzugeben. Die Pfade für jede Themenseite enthalten die Themen-ID. Öffnen Sie Skripte/services.js, und suchen Sie die Funktion fetchTopicIds(), mit der alle Themen-IDs abgerufen werden.

export function fetchTopicIds() {
      const client = getDeliveryClient();
    
      return client.queryItems({
        q: '(type eq "OCEGettingStartedHomePage" AND name eq "HomePage")',
      }).then((data) => {
        const { topics } = data.items[0].fields;
        const topicIds = topics.map(
          (topic) => topic.id,
        );
        return topicIds;
      }).catch((error) => logError('Fetching topic ids failed', error));
    }

Eine Themenseite empfängt eine Themen-ID und erfordert mehrere Datenaufrufe, um alle zugehörigen Daten abzurufen:

  1. Namen des Themas abrufen
  2. Alle Artikel für das angegebene Thema abrufen.
  3. Rufen Sie für jeden Artikel die zugehörigen Auslieferungs-URLs ab.

Suchen Sie die Funktion fetchTopicName(topicId), mit der der Name des Themas abgerufen wird.

export function fetchTopicName(topicId) {
      const client = getDeliveryClient();
      return client.getItem({
        id: topicId,
      }).then((topic) => topic.name)
        .catch((error) => logError('Fetcvhing topic name failed', error));
    }

Suchen Sie die Funktion fetchTopicArticles(topicId), die die Artikeldaten für die Themaseite abruft.

export function fetchTopicArticles(topicId) {
      const client = getDeliveryClient();
      return client.queryItems({
        q: `(type eq "OCEGettingStartedArticle" AND fields.topic eq "${topicId}")`,
        orderBy: 'fields.published_date:desc',
      }).then((data) => {
        const promises = [];
        const articles = data.items;
    
        articles.forEach((article) => {
          // add a promise to the total list of promises to get the article url
          promises.push(
            getRenditionURLs(client, article.fields.image.id)
              .then((renditionUrls) => {
                article.renditionUrls = renditionUrls;
                // Note: the spread operator is used here so that we return a top level
                // object, rather than a value which contains the object
                // i.e we return
                //   {
                //     field1: 'value', field2 : "value", etc
                //   },
                // rather than
                //   {
                //     name: {
                //             field1: 'value', field2 : "value", etc
                //           }
                //    }
                return {
                  ...article,
                };
              }),
          );
        });
    
        // execute all the promises and return all the data
        return Promise.all(promises)
          .then((allArticles) => ({
            topicId,
            articles: flattenArray(allArticles),
          }));
      }).catch((error) => logError('Fetching topic articles failed', error));
    }

Die fetchTopicArticles()-Methode verwendet auch die zuvor ermittelte getRenditionURLs(), um das Bild für den Artikel abzurufen.

Artikelseitendaten

Die Pfade für jede Artikelseite enthalten die Artikel-ID. Öffnen Sie die Skripts/services.js, und suchen Sie die Funktion fetchAllArticlesSimple(), mit der alle Artikel-IDs abgerufen werden, die bei der Vorabwiedergabe jeder Artikelseite verwendet werden.

export function fetchAllArticlesSimple() {
      const client = getDeliveryClient();
      return fetchTopicIds()
        .then((topicIds) => {
          const promises = [];
          topicIds.forEach((topicId) => {
            // add a promise to the total list of promises to get the article url
            promises.push(
              fetchTopicArticlesSimple(client, topicId)
                .then((data) => {
                  const { items } = data;
                  const articles = items.map((item) => (
                    {
                      id: item.id,
                      name: item.name,
                    }
                  ));
                  return articles;
                }),
            );
          });
    
          // execute all the promises and return all the data
          return Promise.all(promises)
            .then((allArticles) => flattenArray(allArticles));
        }).catch((error) => logError('Fetching basic information for all articles failed', error));
    }

fetchAllArticlesSimple() ruft fetchTopicArticlesSimple() auf, um eine vereinfachte Liste der Artikel abzurufen.

function fetchTopicArticlesSimple(client, topicId) {
      return client.queryItems({
        q: `(type eq "OCEGettingStartedArticle" AND fields.topic eq "${topicId}")`,
        orderBy: 'fields.published_date:desc',
      }).then((data) => data)
        .catch((error) => logError('Fetching basic information for topic articles failed', error));
    }

Eine Artikelseite erhält eine Artikel-ID und erfordert mehrere Datenaufrufe, um alle zugehörigen Daten abzurufen:

  1. Rufen Sie die Artikeldetails für den angegebenen Artikel ab.
  2. Rufen Sie für jeden Artikel die zugehörigen Auslieferungs-URLs ab.

Suchen Sie die Funktion fetchArticleDetails(articleId), die die Daten für die Artikelseite abruft. Die Methode verwendet die Funktion getRenditionURL(), die das Bild für den Artikel abruft und außerdem die Funktion getMediumRenditionURL() verwendet, um das Bild für den Autor abzurufen.

export function fetchArticleDetails(articleId) {
      const client = getDeliveryClient();
      return client.getItem({
        id: articleId,
        expand: 'fields.author,fields.image',
      }).then((article) => {
        const { fields } = article;
        const title = fields.author.name;
        const date = fields.published_date;
        const content = fields.article_content;
        const imageCaption = fields.image_caption;
        const { topic } = fields;
        const { name } = article;
        const renditionUrls = getSourceSet(article.fields.image);
        const avatarID = article.fields.author.fields.avatar.id;
        // Get the author's avatar image
        return getRenditionURLs(client, avatarID)
          .then((authorRenditionUrls) => (
            // return an object with just the data needed
            {
              id: articleId,
              name,
              title,
              date,
              content,
              imageCaption,
              renditionUrls,
              authorRenditionUrls,
              topicId: topic.id,
              topicName: topic.name,
            }
          ));
      }).catch((error) => logError('Fetching article details failed', error));
    }

Die fetchArticleDetails()-Methode verwendet auch die zuvor angezeigte getRenditionURLs(), um das Avatarbild abzurufen.

Nachdem unsere Datenabfragen vorliegen, können wir die Antworten in unseren Next.js-Komponenten gerendern.

Next.js-Komponenten

Next.js basiert auf React und React verwendet eine Technologie, die als JSX bezeichnet wird. Dabei handelt es sich um eine HTML-ähnliche Syntaxerweiterung für JavaScript, um den Inhalt wiederzugeben. Auch wenn Sie reinen JavaScript schreiben können, um Daten aus Oracle Content Management wiederzugeben, wird dringend empfohlen, JSX zu verwenden.

Die Blog-Anwendung unterteilt jede Seite in eine Reihe kleinerer Komponenten.

Die nächsten Abschnitte bieten einen Überblick darüber, wie Next.js unsere Anwendung in jeder unserer Komponenten wiedergibt:

Seitenordner

Auf unserer Website möchten wir drei Routen anbieten:

Jede Seite im Seitenverzeichnis Next.js wird als Route für die Anwendung behandelt.

Indexkomponente

Die Homepage besteht aus einer Liste mit einzelnen Themen. Es wird von der Indexkomponente unter pages/index.jsx wiedergegeben.

Die Komponente importiert die API, um Daten aus der Datei services.js abzurufen.

import { getTopicsListPageData } from '../scripts/services';

In getStaticProps(), die während der Erstellungszeit aufgerufen wird, ruft die Komponente alle Daten ab, die zur Wiedergabe der Homepage erforderlich sind.

export async function getStaticProps() {
      const data = await getTopicsListPageData();
      return { props: { data } };
    }

Headerkomponente

Die Indexkomponente verwendet die Kopfdatenkomponente, um den Firmentitel, das Firmenlogo und die Links "Kontakt"/"Info" anzuzeigen.

Es befindet sich in src/components/Header.jsx und empfängt alle zugehörigen Daten als Eigenschaften. Es werden keine zusätzlichen Daten vom Server abgerufen.

TopicsListItem-Komponente

Die Indexkomponente verwendet die Komponente TopicsListItem, um das einzelne Thema in der Liste anzuzeigen.

Die Komponente TopicsListItem, die sich unter src/components/TopicsListItem.jsx befindet, empfängt alle zugehörigen Daten als Eigenschaften. Es werden keine zusätzlichen Daten vom Server abgerufen.

ArticleListPage-Komponente

Auf der Seite "Thema" werden die Artikel im Thema angezeigt, deren ID an die Komponente der URL übergeben wird. Sie wird von der Komponente ArticleListPage in den Seiten/Artikel/[id].jsx wiedergegeben.

Die Komponente importiert die API, um Daten aus der Datei services.js abzurufen.

import { fetchTopicIds, fetchTopicName, fetchTopicArticles } from '../../scripts/services';

Die URLs für die Seite "Themen" sind dynamische URLs, die die Themen-ID als Pfad enthalten. Beispiel-URL-Pfade sind

Wenn Next.js die statische Sitegenerierung für Seiten mit dynamischen URLs verwendet, ruft es getStaticPaths() auf, um alle Pfade für diese Seite abzurufen.

export async function getStaticPaths() {
      const topicIds = await fetchTopicIds();
    
      // Generate the paths we want to pre-render based on posts
      const paths = topicIds.map((topicId) => ({
        params: { id: topicId },
      }));
    
      return {
        paths,
        fallback: false,
      };
    }

Mit der Funktion getStaticProps() werden die Daten für eine einzelne Instanz der Seite "Themen" abgerufen. Die Themen-ID wird aus dem Parameter abgerufen, der an die Methode übergeben wird. Mit der Themen-ID werden dann alle für diese Seite erforderlichen Daten abgerufen.

export async function getStaticProps(context) {
      const { params } = context;
      const { id } = params;
      const [data, topicName] = await Promise.all([fetchTopicArticles(id), fetchTopicName(id)]);
    
      return {
        props: {
          topicId: id,
          topicName,
          data,
        },
      };
    }

ArticesListItem-Komponente

Die Komponente ArticleListPage verwendet die Komponente ArticlesListItem, um die einzelnen Artikel in der Liste anzuzeigen.

Die Komponente ArticlesListItem befindet sich in src/components/ArticlesListItem.jsx und empfängt alle zugehörigen Daten als Eigenschaften. Es werden keine zusätzlichen Daten vom Server abgerufen.

ArticleDetailsPage-Komponente

Auf der Seite "Artikel" werden Details des Artikels angezeigt, dessen ID an die URL übergeben wird. Sie wird von der Komponente ArticleDetailsPage in den Seiten/Artikel/[id].jsx wiedergegeben.

Die Komponente importiert die API, um Daten aus der Datei services.js abzurufen.

import { fetchAllArticlesSimple, fetchArticleDetails } from '../../scripts/services';

Die URLs für die Artikelseite sind dynamische URLs, die die Artikel-ID als Pfad enthalten. Beispiel-URL-Pfade sind

Wenn Next.js die statische Sitegenerierung für Seiten mit dynamischen URLs verwendet, ruft es getStaticPaths() auf, um alle Pfade für diese Seite abzurufen.

export async function getStaticPaths() {
      const articles = await fetchAllArticlesSimple();
    
      // Generate the paths we want to pre-render based on posts
      return {
        paths: articles.map((article) => ({
          params: { id: article.id },
        })),
        fallback: true,
      };
    }

Mit der Funktion getStaticProps() werden die Daten für eine einzelne Instanz der Artikelseite abgerufen. Die Artikel-ID wird aus dem an das Verfahren übergebenen Parameter ermittelt. Die Artikel-ID wird dann verwendet, um alle für diese Seite erforderlichen Daten abzurufen.

export async function getStaticProps(context) {
      const { params } = context;
      const { id } = params;
      const data = await fetchArticleDetails(id);
      return {
        props: {
          data,
        },
      };
    }

Sowohl die Komponenten "Index" als auch "ArticleDetailsPage" verwenden die Komponenten "Breadcrumbs" und "Breadcrumb", um die Navigationspfade oben auf der Seite anzuzeigen, sodass der Benutzer zur Seite "Thema" oder zur Homepage zurückkehren kann. Beide Komponenten erhalten alle ihre Daten als Eigenschaften. Sie erhalten keine zusätzlichen Daten vom Server.

Aufgabe 3: Anwendung auf Deployment vorbereiten

Nachdem wir unsere Next.js-Blog-Website erstellt haben, müssen wir sie auf einem lokalen Entwicklungsserver sehen, damit wir Probleme debuggen und die Anwendung vor ihrem Go-Live in der Vorschau anzeigen können.

Bereiten Sie die Anwendung in zwei Schritten vor:

  1. Lokalen Entwicklungsserver hochfahren
  2. Verwenden von Skripten zum Erstellen und Ausführen der Anwendung in Entwicklung und Produktion

Lokalen Entwicklungsserver hochfahren

Sie können einen Entwicklungsserver lokal starten, indem Sie den folgenden Befehl ausführen.

npm run dev

Öffnen Sie dann Ihren Browser zu http://localhost:3000, um Ihre Site in Aktion anzuzeigen.

Hinweis: Dadurch werden die Seiten nicht vorab wiedergegeben. Im nächsten Abschnitt wird beschrieben, wie Sie die Seiten im Voraus anzeigen.

Verwenden von Skripten zum Erstellen und Ausführen der Anwendung in Entwicklung und Produktion

Für die Produktion wird das Build-Skript verwendet, um die Site statisch zu generieren.

npm run build

Mit dem Startskript wird ein Node.js-Server gestartet, der die statisch generierten Seiten bedient.

npm run start