Loading...
nextjs 14 typescript contentful app router - full example
Author Cloudapp
E.G.

Next.js 14 - Komplettes Beispiel - Typescript / App Router / Contentful mit GraphQL - Teil 1

8. März 2024
Inhaltsverzeichnis

Lassen Sie uns eine völlig neue Website erstellen, die mit folgendem Tech-Stack betrieben wird:

  • Next.js 14 - Als modernes Web Framework für Frontend und Backend

  • App Router - Damit wir das Beste aus dem Project rausholen können und der Pages Router ist nicht mehr aktuell

  • Contentful - Unser headless CMS

  • Typescript - Typisiertes Javascript

Dies ist der erste Beitrag einer Reihe, in der wir eine Website von Grund auf erstellen werden. Zuerst beginnen wir mit der Projektinitialisierung, dann erstellen wir das Contentful-Konto und als letzten Schritt integrieren wir Contentful als Headless CMS in unser Next.js-Projekt. In den folgenden Beiträgen werden wir tiefer in das Projekt eindringen und Funktionen wie Mehrsprachigkeitsunterstützung, Benutzerregistrierung/-authentifizierung, erweiterte Suche mit Algolia und vieles mehr hinzufügen.

Alle verwendeten Services sind kostenlos und gut geeignet für kleinere Projekte.

Projekt erstellen mit create-next-app

Wir benutzen die "latest" Version des create-next-app pakets

npx create-next-app@latest
create-next-app
create-next-app

Ich verwende VS Code für die Entwicklung, also bitte installieren Sie VS Code https://code.visualstudio.com/download

Öffnen Sie VSCode und falls Sie einen Mac verwenden, dann Command + Shift + P, dies öffnet die Befehlspalette von VSCode, und tippen Sie nun „shell“ ein. Sie sollten „Shell-Befehl: Befehl 'Code' im Pfad installieren“ im Dropdown-Menü sehen. Bitte wählen Sie es aus und jetzt ist VSCode in Ihrem Pfad. So können Sie in Ihren zuvor erstellten Ordner springen und tippen

code .

dieser Befehl öffent VSCode direkt im Projektverzeichnis. Jetzt register wir uns noch bei www.contentful.com und schon sind wir ready. Nach dem ersten Login sollten Sie „Von Grund auf neu starten“ auswählen.

Contentful start screen
Contentful start screen

Erstellen der Contentful API Token & Space ID

Jetzt erstellen wir die benötigten API-Schlüssel für unsere .env.local-Datei. Zuerst Space_ID, Access_Token und Preview_Access_Token und dann Management_Token für Schreib-/Einfügeoperationen.

Contentful start right flyout for api keys - part 1
Contentful start right flyout for api keys - part 1
Contentful start right flyout for api keys - part 2
Contentful start right flyout for api keys - part 2
Contentful start right flyout for api keys - part 3
Contentful start right flyout for api keys - part 3
Contentful start right flyout for api keys - part 4
Contentful start right flyout for api keys - part 4

Management Token (CMA)

Contentful right flyout for Content Management Api Key
Contentful right flyout for Content Management Api Key
Contentful pop-up new CMA Api Key
Contentful pop-up new CMA Api Key

Env File und Npm Packages

Erstellen wir nun die Datei .env.local für die Umgebungsvariablen im Projektverzeichnis

##.env.local##
CONTENTFUL_SPACE_ID=xxxx
CONTENTFUL_ACCESS_TOKEN=xxxx
CONTENTFUL_PREVIEW_ACCESS_TOKEN=xxxx
CONTENTFUL_MANAGEMENT_TOKEN=xxxx
CONTENTFUL_PREVIEW_SECRET=xxxx

Npm pakete hinzufügen

npm install @graphql-codegen/cli graphql graphql-request 
npm install @graphql-codegen/typescript-graphql-request @graphql-codegen/introspection

Nun erstellen wir die Datei codegen.ts im Projektverzeichnis

##codegen.ts##
// Purpose: Configuration for GraphQL Code Generator
import { CodegenConfig } from "@graphql-codegen/cli";

const endpointOverride = process.env.CONTENTFUL_GRAPHQL_ENDPOINT;
const productionEndpoint = "https://graphql.contentful.com/content/v1/spaces";
export const endpoint = `${endpointOverride || productionEndpoint}/${
  process.env.CONTENTFUL_SPACE_ID
}`;

export const config: CodegenConfig = {
  overwrite: true,
  ignoreNoDocuments: true,
  schema: [
    {
      [endpoint || ""]: {
        headers: {
          Authorization: `Bearer ${process.env.CONTENTFUL_PREVIEW_ACCESS_TOKEN}`,
        },
      },
    },
  ],
  generates: {
    "src/lib/__generated/graphql.schema.json": {
      plugins: ["introspection"],
    },
    "src/lib/__generated/graphql.schema.graphql": {
      plugins: ["schema-ast"],
    },
    "src/lib/__generated/sdk.ts": {
      documents: ["src/lib/graphql/**/*.graphql"],
      plugins: [
        "typescript",
        "typescript-operations",
        "typescript-graphql-request",
      ],
      config: {
        rawRequest: false,
        inlineFragmentTypes: "combine",
        skipTypename: false,
        exportFragmentSpreadSubTypes: true,
        dedupeFragments: true,
        preResolveTypes: true,
      },
    },
  },
};

export default config;

Wir müssen diese zwei Zeilen Code in der Datei package.json hinzufügen, damit später die Befehle funktionieren

##script section of package.json##
"graphql-codegen:generate": "graphql-codegen -r dotenv/config --config codegen.ts dotenv_config_path=.env.local",
"graphql-codegen:watch": "graphql-codegen --watch -r dotenv/config --config codegen.ts dotenv_config_path=.env.local"
##package.json##
{
  "name": "nextjs13_5-typescript-app-router-contentful",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "graphql-codegen:generate": "graphql-codegen -r dotenv/config --config codegen.ts dotenv_config_path=.env.local",
    "graphql-codegen:watch": "graphql-codegen --watch -r dotenv/config --config codegen.ts dotenv_config_path=.env.local"
  },
  "dependencies": {
    "@graphql-codegen/cli": "^5.0.2",
    "@graphql-codegen/introspection": "^4.0.3",
    "@graphql-codegen/typescript-graphql-request": "^6.2.0",
    "graphql": "^16.8.1",
    "graphql-request": "^6.1.0",
    "next": "14.1.3",
    "react": "^18",
    "react-dom": "^18"
  },
  "devDependencies": {
    "@types/node": "^20",
    "@types/react": "^18",
    "@types/react-dom": "^18",
    "autoprefixer": "^10",
    "eslint": "^8",
    "eslint-config-next": "13.5.6",
    "postcss": "^8",
    "tailwindcss": "^3",
    "typescript": "^5"
  }
}

Verzeichnisse und Dateien anlegen für GraphQL

Erstellen der Dateien src/lib und client.ts

##src/lib/client.ts##
import { GraphQLClient } from "graphql-request";

import { getSdk } from "@/lib/__generated/sdk";
import { endpoint } from "../../codegen";

const graphQlClient = new GraphQLClient(endpoint, {
  headers: {
    Authorization: `Bearer ${process.env.CONTENTFUL_PREVIEW_ACCESS_TOKEN}`,
  },
});

export const client = getSdk(graphQlClient);

Erstellen Sie einen Ordner „graphql“ unter src/lib/ und innerhalb des Ordners „graphql“ erstellen Sie diese .graphql-Dateien (Sie können sie vom Github-Repo bekommen)

##graphql files##
authorFields.graphql
imageFields.graphql
pageBlogPost.graphql
pageBlogPostCollection.graphql
richImageFields.graphql
seoFields.graphql

Jetzt erstellen wir einen neuen Ordner namens contentfulsync im Projektstammverzeichnis und fügen dann diese Zeilen im Skriptbereich der package.json hinzu

npm install contentful-cli

Lassen Sie uns die Importkonfigurationsdatei für die contentful-cli unter contentfulsync/import/config/contentful-import-config.json erstellen

##contentfulsync/import/config/contentful-import-config.json##
{
  "contentFile": "./contentfulexport/import/export.json"
}

Neues Verzeichnis erstellen contentfulsync/export/config

##contentfulsync/export/config/contentful-import-config.json##
{
  "exportDir": "contentfulsync",
  "contentFile": "export.json",
  "downloadAssets": false
}

Daten in den Contentful Space importieren

Jetzt können wir den Import durchführen

npm run cf-import

Nachdem dies erledigt ist, sind die Inhaltstypen und der Inhalt in unserem Contentful Space vorhanden.

Und das Frontend ?

Um die Daten im Frontend anzeigen zu können, müssen wir fehlende npm-Pakete installieren.

npm install @contentful/rich-text-react-renderer tailwind-merge

Als nächster Schritt fügen wir diese Komponenten unter src/components hinzu (erstellen Sie den Komponentenordner, falls er nicht existiert)

##Components##
ArticleContent.component.tsx
ArticleImage.component.tsx
CtfImage.component.tsx
CtfRichText.component.tsx

Jetzt noch die Datei page.tsx im Verzeichnis src/app/ anpassen

import { ArticleContent } from "@/components/contentful/ArticleContent.component";
import { client } from "@/lib/client";
import { notFound } from "next/navigation";

async function BlogPostPage() {
  const [blogPagedata] = await Promise.all([
    client.pageBlogPost({
      slug: "testblogpost",
    }),
  ]);

  const blogPost = blogPagedata.pageBlogPostCollection?.items[0];

  if (!blogPost) {
    // If a blog post can't be found,
    // tell Next.js to render a 404 page.
    return notFound();
  }

  const relatedPosts = blogPost?.relatedBlogPostsCollection?.items;

  if (!blogPost || !relatedPosts) return null;

  return (
    <>
      {/* <Container className="max-w-4xl mt-8"> */}
      <div className="mt-4" />
      <ArticleContent article={blogPost} />
      {/* </Container> */}
    </>
  );
}

export default BlogPostPage;

Deployment

Dev Server starten

npm run dev

führt zu einem Fehler, da die Domain, von der die Bilder bereitgestellt wurden „images.ctfassets.net“, nicht konfiguriert ist. Gehen wir also zu unserer next.config.js Datei und ändern sie, sodass sie folgendermaßen aussieht:

/** @type {import('next').NextConfig} */
const nextConfig = {
  images: { domains: ["images.ctfassets.net"] },
  reactStrictMode: true,
};

module.exports = nextConfig;

Nun sollte der Entwicklungsserver starten und wir können die URL http://localhost:3000 verwenden, um das Ergebnis zu sehen.

Preview Page
Preview Page

Das war's. Die Grundlagen sind geschaffen und im nächsten Beitrag werden wir mit dem Frontend fortfahren, dann wie wir zusätzliche Sprachen handhaben können, Benutzerregistrierung/-anmeldung und vieles mehr. Bleiben Sie gespannt und natürlich dran.

Github Repo

https://github.com/cloudapp-dev/nextjs13_5-typescript-app-router-contentful

Wenn Ihnen gefällt, was Sie sehen, dann unterstützen Sie mich bitte mit einem "Clap" oder folgen Sie mir auf medium.com.

Verwandte Artikel