Управление контентом может быть утомительной и трудоемкой задачей, но что, если я скажу вам, что есть инструмент, который может упростить этот процесс и сделать его легким? Представляем Contentlayer, мощный инструмент, который преобразует ваш контент в данные и упрощает работу с файлами .md и .mdx. С Contentlayer все, что вам нужно сделать, это установить и настроить его, и вы можете начать писать в предпочитаемом формате файла. Лучшая часть? Contentlayer автоматически добавляет типы к вашим данным, гарантируя, что ваш контент всегда типобезопасен. Попрощайтесь с трудностями управления контентом и познакомьтесь с более оптимизированным процессом с Contentlayer и Next.js.

Настройка приложения Next.js

Чтобы создать приложение Next.js с серверными компонентами, мы будем использовать новую функцию appDir. Просто добавьте флаг —experimental-app в свою команду, и для вас будет создан новый каталог приложения. Стоит отметить, что все в этом каталоге по умолчанию будет считаться серверным компонентом.

Для начала выполните любую из следующих команд:

npx create-next-app@latest --experimental-app
# or
yarn create next-app --experimental-app
# or
pnpm create next-app --experimental-app

После того, как ваше приложение Next.js создано, рекомендуется очистить весь ненужный код, чтобы ваш проект был организован и эффективен.

Установить контентный слой

Чтобы использовать Contentlayer, вы должны установить пакет Contentlayer и плагин Next.js. Чтобы установить эти пакеты, выполните следующие команды:

npm install contentlayer next-contentlayer
#or
yarn add contentlayer next-contentlayer
#or
pnpm add contentlayer next-contentlayer

Конфигурация для Contentlayer

Чтобы интегрировать контентный слой в процессы next dev и next build, нам нужно обернуть nextConfig методом withContentlayer.

// next.config.js

const { withContentlayer } = require('next-contentlayer');

/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    appDir: true,
  },
};

module.exports = withContentlayer(nextConfig);

Кроме того, нам нужно обновить наш файл tsconfig.json или jsconfig.json со следующими изменениями:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "contentlayer/generated": ["./.contentlayer/generated"]
    }
  },
  "include": ["next-env.d.ts", "**/*.tsx", "**/*.ts", ".contentlayer/generated"]
}

Определение схемы публикации

Начнем с того, что расскажем о важности определения схемы поста для нашего блога. Эта схема поможет Contentlayer преобразовать наш контент в данные, которые можно использовать в нашем блоге. Чтобы создать эту схему, нам нужно создать новый файл с именем contentlayer.config.js в корне нашего проекта и включить следующий код:

import { defineDocumentType, makeSource } from 'contentlayer/source-files';

const Post = defineDocumentType(() => ({
  name: 'Post',
  filePathPattern: `**/*.md`,
  fields: {
    title: {
      type: 'string',
      required: true,
    },
    description: {
      type: 'string',
      required: true,
    },
    keywords: {
      type: 'string',
      required: true,
    },
    date: {
      type: 'string',
      required: true,
    },
  },
  computedFields: {
    url: {
      type: 'string',
      resolve: (doc) => doc._raw.flattenedPath,
    },
  },
}));

export default makeSource({
  contentDirPath: 'posts',
  documentTypes: [Post],
});

Этот код будет определять тип документа Post, который будет представлять наши сообщения в блоге. Предполагается, что каждое сообщение представляет собой файл .md, расположенный в каталоге сообщений. Эта схема будет включать следующие свойства:

  • title: обязательная строка, которая будет использоваться в качестве заголовка сообщения в блоге.
  • description: обязательная строка, которая будет использоваться в качестве описания сообщения в блоге.
  • date: обязательная строка, которая будет использоваться в качестве даты сообщения в блоге.
  • url: вычисляемая строка, которая будет принимать имя файла без расширения и использоваться в качестве URL-адреса сообщения в блоге.

Важно отметить, что заголовок сообщения в блоге также будет использоваться в качестве h1 сообщения в блоге, поэтому никакие другие теги h1 не должны использоваться в содержании. Определив схему Post, мы можем легко преобразовать наш контент в данные, которые можно использовать в нашем блоге.

Добавить сообщения

Чтобы заполнить наш блог, нам нужно добавить некоторый контент. Начните с создания нового каталога с именем post и добавьте туда все свои сообщения.

Например, вот пример сообщения с названием what-is-contentlayer.md, расположенного в каталоге сообщений:

---
title: 'What is Contentlayer?'
description: 'Demo description'
keywords: 'content, preprocessor, type-safe'
date: '2022-02-22'
---

**Contentlayer makes working with content easy.** It is a content preprocessor that validates and transforms your content into type-safe JSON you can easily import into your application.

Важное примечание. Обязательно запустите среду разработки сейчас. Это создаст каталог .contentlayer, содержащий весь наш контент в формате .json. Это означает, что наш контент был преобразован в данные, что упрощает управление им.

Страница блогов

Чтобы продемонстрировать все наши сообщения в блоге, мы заменим домашнюю страницу (app/page.tsx) следующим кодом:

import Link from 'next/link';
import { allPosts } from 'contentlayer/generated';

export const metadata = {
  title: 'Blog',
  description:
    'Discover insights, tips, and techniques on web development.',
  openGraph: {
    title: 'Blog',
    description:
      'Discover insights, tips, and techniques on web development.',
    siteName: 'Blog Website',
    locale: 'en-US',
    type: 'website',
  },
  twitter: {
    title: 'Blog',
    description:
      'Discover insights, tips, and techniques on web development.',
  },
};

export default function Home() {
  return (
    <main>
      <h1>Blog</h1>
      {allPosts
        .sort((a, b) => {
          if (new Date(a.date) > new Date(b.date)) {
            return -1;
          }
          return 1;
        })
        .map((post) => (
          <Link key={post.url} href={`/blog/${post.url}`}>
            <p>{post.title}</p>
          </Link>
        ))}
    </main>
  );
}

Мы импортируем все наши сообщения в блоге из contentlayer/generated и отображаем их в виде ссылок, отсортированных по дате. Деструктурируя каждый объект публикации, мы можем легко получить доступ к его свойствам URL и заголовка.

Обратите внимание, что мы используем новую дату (b.date) — новую дату (a.date) вместо оператора if для сортировки сообщений в порядке убывания. Мы также переименовали компонент в Blog для ясности. Кроме того, мы включили метаданные для целей SEO, используя новый формат метаданных, доступный в next.js 13.

Создание единого макета поста в блоге

Чтобы отобразить каждый пост в блоге на отдельной странице, нам нужно создать страницу-слаг. Эта страница будет использовать определенный формат URL для идентификации сообщения. Мы можем создать файл с именем [slug]/page.tsx и поместить в него следующее содержимое:

import { allPosts } from 'contentlayer/generated';

export async function generateStaticParams() {
  return allPosts.map((post) => ({
    slug: post.url,
  }));
}

export async function generateMetadata({ params }) {
  const post = allPosts.find((post) => post.url === params.slug);

  return {
    title: post.title,
    description: post.description,
    openGraph: {
      title: post.title,
      description: post.description,
      siteName: 'Blog Website',
      locale: 'en-US',
      type: 'article',
    },
    twitter: {
      title: post.title,
      description: post.description,
    },
  };
}

export default async function Blog({ params }) {
  const post = allPosts.find((post) => post.url === params.slug);

  return (
    <article>
      <header>
        <h1>{post.title}</h1>
        <time>{post.date}</time>
      </header>
      <section
        dangerouslySetInnerHTML={{ __html: post.body.html }}
      />
    </article>
  );
}
  • Функция generateStaticParams() создает новый объект из allPosts только с одним свойством, slug, и присваивает его post.url. Затем этот объект используется для получения запрошенного сообщения в блоге.
  • Функция generateMetadata() генерирует метаданные для сообщения в блоге, такие как заголовок, описание и теги социальных сетей.
  • Компонент Blog отображает заголовок, дату и текст сообщения.

Итак, вы успешно создали приложение для блога. Вы можете создать свой собственный пользовательский интерфейс и начать писать свои собственные сообщения в блоге. Продолжайте учиться и делиться своими знаниями с другими