Настройка базового приложения Next.js локально [Создание персонального сайта-блога, часть 2]

Это вторая часть серии статей «Создание личного сайта-блога». В этой серии мы настроим бесплатную CMS для хранения контента блога на Railway, создадим приложение React с помощью Next.js для генерации статических сайтов и TailwindCSS для представления статей и разместим его на Netlify.

Все статьи:
Часть 1: Размещение бесплатной Strapi CMS на Railway
Часть 2: Настройка базового приложения Next.js локально

Теперь, когда базовая CMS установлена на Railway и Cloudinary настроен для работы с изображениями, следующим шагом будет… создание приложения Next.

Это приложение Next будет потреблять контент, предоставляемый CMS, и представлять его на веб-странице. В этой части цикла будет создана и локально настроена базовая домашняя страница со списком записей блога.

Так что давайте просто перейдем к этому. Первое, что вам нужно создать, это новое приложение Next.js. Это можно сделать с помощью этой простой команды:

npx create-next-app@latest

Войти в полноэкранный режим Выйти из полноэкранного режима

После ее выполнения появится запрос на имя приложения — укажите его, и проект будет создан.

Прежде чем начать работу над приложением, давайте установим некоторые зависимости, которые пригодятся в дальнейшем — TailwindCSS для стилизации приложения и Apollo Client для работы с GraphQL.

Сначала установим TailwindCSS.

yarn add tailwindcss postcss autoprefixer
npx tailwindcss init -p
Вход в полноэкранный режим Выход из полноэкранного режима

После выполнения команды init будет создан файл tailwind.config.js. Вам нужно внести несколько изменений в созданный файл, чтобы все работало правильно.

Замените пустой массив content на:

content: [
    "./pages/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}",
  ],
Войти в полноэкранный режим Выйти из полноэкранного режима

Также необходимо импортировать правила TailwindCSS в файл ./styles/globals.css:

@tailwind base;
@tailwind components;
@tailwind utilities;

Войти в полноэкранный режим Выход из полноэкранного режима

Теперь вы закончили с настройкой TailwindCSS. Давайте перейдем к клиенту Apollo.

yarn add @apollo/client graphql

Вход в полноэкранный режим Выход из полноэкранного режима

Вот и все! Вы готовы создать свою страницу блога, управляемую GraphQL.

Сначала вам нужно настроить Apollo Client, который будет работать как «шлюз» к вашему GraphQL API. Создайте новый файл в корне проекта под названием apollo-client.js (вы можете назвать его как угодно, TBH).

import { ApolloClient, InMemoryCache } from "@apollo/client";

const client = new ApolloClient({
    uri: "https://[YOUR-CMS-GRAPHQL-URL]",
    cache: new InMemoryCache(),
});

export default client;

Войдите в полноэкранный режим Выйдите из полноэкранного режима

Когда все готово, пришло время использовать это! Для начала вам нужно получить список всех записей блога, которые будут отображаться на главной странице. Вы будете использовать функцию Static Site Generation в Next.js — для этого необходим метод getStaticProps.


Побочное замечание — почему именно SSG?

Поскольку в этой серии уроков мы говорим о бесплатной настройке блога, мы ограничены в производительности. CMS, установленная на бесплатном Railway tier, не является демоном скорости, приложение Next.js с SSR, установленное на бесплатном Netlify, также будет довольно медленным. Таким образом, SSG кажется лучшим вариантом, даже если каждое изменение в нашем блоге потребует перестройки приложения. Если бюджет не является для вас проблемой, то вы можете подумать о других вариантах, но это не тема этой серии.


Прежде чем мы продолжим, давайте добавим еще два поля в конфигурацию записи блога. Откройте репозиторий для вашей Strapi CMS и запустите его в режиме разработки (yarn develop). Войдите в систему и перейдите к конструктору Content-Type Builder. Сначала вам нужно будет создать новый тип с именем Tag.

У него есть ID и имя, которое должно быть уникальным.

Когда это будет сделано, вы будете готовы «обновить» тип записи Blog. В Content-Type Builder откройте Post и добавьте два новых поля. Первое — это excerpt — короткий текст, который будет представлен на вашей домашней странице. Оно должно быть типа string и желательно иметь некоторую максимальную длину (в моем случае 250 символов). Он также должен быть обязательным.

Теперь необходимо добавить Tags. Это будет поле типа Relation, а отношение будет Many-to-Many, так как один пост может иметь несколько тегов, и каждый тег может принадлежать нескольким постам. Сделайте это следующим образом:

Теперь зайдите в терминал и зафиксируйте все изменения, которые были сделаны в ваших конфигурационных файлах Strapi. А затем запустите изменения для восстановления CMS, размещенной на Railway:

git push

Войдите в полноэкранный режим Выйдите из полноэкранного режима

Когда приложение на Railway будет восстановлено — войдите в систему и измените разрешения пользователя Public, чтобы вы могли запрашивать Tags.

Теперь вы можете получить данные в getStaticProps в файле index.js вашего приложения Next.js. Добавьте это в нижней части pages/index.js.

export async function getStaticProps() {
  const { data } = await client.query({
    query: gql`
      query Posts {
        posts(
          sort: "publishedAt:desc"
          pagination: { limit: 5 }
          filters: { publishedAt: { notNull: true } }
        ) {
          data {
            attributes {
              title
              slug
              cover {
                data {
                  attributes {
                    url
                  }
                }
              }
              excerpt
              tags {
                data {
                  attributes {
                    tagId
                    name
                  }
                }
              }
            }
          }
        }
      }
    `,
  });

  return {
    props: {
      posts: data.posts.data,
    },
  };
}

Вход в полноэкранный режим Выйти из полноэкранного режима

Что это делает? При каждой сборке (yarn build) Next будет выполнять этот запрос перед «рендерингом» страницы/созданием статического вывода страницы. Это означает, что вам не понадобятся индикаторы загрузки на вашей веб-странице, потому что данные уже будут получены. Недостатком этого, конечно, является то, что вам придется перестраивать приложение при каждом изменении содержимого в CMS. Но для персональных блогов это довольно хорошее и дешевое решение.

Вы загружаете только самые важные данные, которые будут показаны на домашней странице. Итак, давайте создадим простую домашнюю страницу.

Вы начнете с создания нового компонента — карточки для предварительного просмотра записи в блоге. Создайте новый файл components/BlogPostPreview.jsx (если нет папки component — создайте ее).

import Image from "next/image";
import React from "react";

const BlogPostPreview = ({ post }) => {
  return (
    <div className="max-w-sm rounded overflow-hidden shadow-lg">
      <a href="#">
        <Image
          className="w-full"
          src={post.attributes.cover.data.attributes.url}
          alt=""
          width={1000}
          height={480}
          objectFit="cover"
        />
        <div className="px-6 py-4">
          <div className="font-bold text-xl mb-2">{post.attributes.title}</div>
          <p className="text-gray-700 text-base">{post.attributes.excerpt}</p>
        </div>
      </a>
      <div className="px-6 pt-4 pb-2">
        {post.attributes.tags.data.map((tag) => (
          <a href="#" key={tag.attributes.tagId}>
            <span className="inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2">
              {tag.attributes.name}
            </span>
          </a>
        ))}
      </div>
    </div>
  );
};

export default BlogPostPreview;

Войдите в полноэкранный режим Выйдите из полноэкранного режима

Здесь вы получаете один prop — post. В нем содержится вся найденная информация. Затем мы создаем простую карточку с изображением обложки, заголовком, отрывком и списком тегов. Конечный результат будет выглядеть примерно так:

Как видите, в коде есть несколько пустых тегов a — на последующих этапах этой серии уроков вы будете их использовать, не волнуйтесь.

Теперь, наконец, пришло время показать посты вашего блога. В pages/index.js используйте только что созданный компонент.

export default function Home({ posts }) {
  return (
    <div className="flex flex-col items-center">
      <h1 className="text-3xl uppercase font-serif font-bold my-8">
        My personal blog
      </h1>
      <section className="grid grid-cols-3 gap-4">
        {posts.map((post) => (
          <BlogPostPreview post={post} key={post.attributes.slug} />
        ))}
      </section>
    </div>
  );
}

Войти в полноэкранный режим Выход из полноэкранного режима

Еще одна вещь, прежде чем вы создадите этот компонент — если вы используете Cloudinary для изображений (как это было сделано во второй части этой серии), вам нужно будет добавить домен Cloudinary в next.config.js. Это необходимо для того, чтобы вы могли использовать компонент next/image вместо тега img.

Ух ты, это была отличная поездка. Давайте, наконец, построим это! Запустите

Конечно, не забудьте создать несколько тегов и постов (вам нужно будет создать тег, прежде чем вы сможете использовать его в посте). Также, поскольку вы добавили несколько новых обязательных полей — обновите существующие посты, чтобы в них была заполнена вся необходимая информация.

Вот и все. Это конец второй части этой серии уроков. В следующей части вы создадите страницу записей блога. До встречи!

Оцените статью
devanswers.ru
Добавить комментарий