В этой статье вы узнаете:
- о назначении CMS;
- как использовать Strapi;
- как с помощью Next.js и Strapi создавать статические сайты.
Введение
Предположим, что вы создаете блог при помощи Next.js. Для добавления в него поста нужно будет сделать следующее:
- перейти в каталог
/pages/article
проекта; - создать в нем файл
1.js
, чтобы Next.js отрисовывал пост при переходе пользователя по маршруту/article/1
; - в дальнейшем для добавления других постов понадобится создать
2.js
,3.js
и т.д.
И хоть такое решение вполне возможно, обратите внимание, что оно постепенно становится все более утомительным, повторяющимся и времязатратным. Для добавления контента нужно будет всякий раз создавать новый файл.
Есть ли способ упростить этот процесс?
Здесь нам поможет CMS (система управления контентом). С помощью нее можно редактировать содержимое сайта без каких-либо затруднений. Прошло то время, когда для внесения простейших правок в сайт приходилось перелопачивать кучу строк кода. Используя CMS, можно изменять или загружать посты всего в несколько кликов.
Одним из известных примеров CMS является Strapi.
Ключевое преимущество CMS в том, что она позволяет автору писать посты без лишних хлопот и использования кода. Для блогеров такой вариант оказывается очень кстати, так как существенно облегчает им работу.
В общем, если вы хотите упростить управление блогом, то CMS очень пригодится.
Приступим!
CMS
Настройка
Для запуска Strapi выполните в терминале:
Следующая команда запустит процесс настройки:
Вывод:
Как видите, Strapi предлагает настроить проект. Для этого перейдите на страницу localhost:1337/admin
и введите учетные данные для запуска CMS.
После создания учетной записи перед вами возникнет следующая страница:
С первой страницей мы разобрались. Далее познакомимся с плагином Content-Types.
Content-Types builder
Согласно документации Strapi, это один из важнейших плагинов. Здесь можно создавать коллекции и отдельные типы. Все это мы разберем поочередно.
В боковой панели кликните по “Content-Types Builder” в категории Plugins.
Сначала мы создадим простой тип коллекции. Для этого кликните “Create new collection type”.
В диалоговом окне пропишите “Display name” как “Article” и кликните “Continue”:
После этого Strapi предложит добавить поля в новый тип коллекции. Создайте поле “Title” и кликните “Finish” для продолжения:
Далее кликните “Add another field”, а затем “Rich Text”. Здесь укажите имя “Body”:
Давайте подытожим, что мы сделали к этому моменту:
- создали тип коллекции “Article”;
- сообщили Strapi, что в наших статьях будет по два поля;
- первое поле “Title”, имеющее тип Text;
- второе поле “Body”, имеющее тип Rich Text.
Это означает, что можно создать коллекцию статей, которые затем будет отрисовывать Next.js.
Осталось только сохранить изменения. Кликните “Save” в верхнем правом углу:
Если все пройдет успешно, в категории Collection Types должен появиться пункт “Articles”.
Все прошло гладко, и теперь у нас есть коллекция “Articles”.
Далее нужно создать отдельный тип. Кликните в боковой панели “Create new single type”.
Назовите этот тип “About Me” и присвойте ему текстовое поле с именем “Body”:
Кликните “Save”, чтобы завершить внесение изменений. Теперь тип “About Me” должен появиться там же в боковой панели.
На этом этапе мы проделали следующее:
- сообщили Strapi, что нам нужен отдельный тип с именем “About Me”:
- этот тип будет содержать всего одно текстовое поле с именем “Body”.
Проще говоря, отдельный тип служит для контента, который не относится к коллекции (например, меню ресторана, страница About Me или футер).
А теперь напишем первую статью.
Написание статей
Кликните в боковой панели “Articles”, а затем “Add New Articles”. Здесь вы можете добавлять новые элементы в коллекцию “Articles”.
Теперь вы увидите страницу создания записи для коллекции. Внесем сюда какую-нибудь информацию. Поле Rich Text принимает разметку Markdown.
После введения информации в поля кликните “Save”. Когда Strapi сохранит запись, жмите “Publish”.
Вывод:
Поздравляю! Вы опубликовали свой первый пост!
На этом раздел заканчивается, и мы переходим к типу “About Me”.
Страница About Me
В боковой панели кликните “About Me” и введите в текстовое поле какой-нибудь текст. По завершению нажмите “Save”.
В завершении опубликуйте созданную запись.
Вот и все. Далее мы перейдем к извлечению этих данных с помощью запросов GET.
Получение данных
После того, как мы написали посты, нам нужно выполнить простой запрос на получение, чтобы отобразить их во фронтенде. Пока выполним запрос GET
из командной строки:
Вот результат:
Вместо списка постов мы получили ошибку 403. Чтобы от нее избавиться, нужно установить публичный доступ в настройках безопасности Strapi.
Для этого кликните по “Settings” в боковой панели.
Далее в разделе “Users & Permissions Plugin” кликните “Roles”:
В разделе “Roles” выберите “Public”:
После этого промотайте вниз к разделу “Permissions”. В выпадающем меню “Application” отметьте следующие опции:
Таким образом мы сообщили Strapi, что следующая информация должна быть публичной:
- содержимое отдельного типа “About Me” (то есть действие
find
); - содержимое и количество элементов, находящихся в коллекции “Articles”. Другими словами, действия
count
,findone
иfind
являются публичными.
Проверим все это. Для получения списка статей выполните в терминале следующую команду:
Ожидаемый вывод:
Как видите, мы получили массив элементов из коллекции “Articles”.
Далее для получения содержимого типа “About Me” выполните:
Ожидаемый вывод:
Отлично! Все работает, как надо.
На этом очередной раздел закончен. Далее мы займемся разработкой фронтенд-части с помощью Next.js, чтобы отображать статьи на веб-странице.
Фронтенд
Установка
Для инициализации проекта Next.js выполните в терминале:
Внутри проекта перейдите в файл /pages/index.js
и найдите следующий фрагмент кода:
Удалите код между родительскими тегами div
. В итоге /pages/index.js
должен выглядеть так:
import Head from "next/head";
export default function Home() {
return (
<div>
<Head>
<title>Home</title>
</Head>
<h1>Welcome home!</h1>
</div>
);
}
- строка 7: устанавливаем заголовок для домашней страницы.
Выполните код. Результат будет следующим:
Далее мы перейдем к настройке переменных конфигурации.
Переменные конфигурации
Нас интересует переменная url
. Она будет указывать на расположение Strapi. В процессе разработки URL-адресом Strapi будет http://localhost:1337/
.
В корне проекта создайте каталог config
, а в нем файл next.config.js
.
В этом файле пропишите следующий код:
const production = process.env.NODE_ENV === "production";
export const url = production
? "https://www.yoursite.com"
: "https://localhost:1337";
- строка 1: логическое значение
production
будет указывать, находимся ли мы в среде продакшена; - строка 3: если да, то переменная
url
должна иметь значением URL-адрес развернутого экземпляра Strapi. В противном случае она должна указывать наhttps://localhost:1337/
.
Далее мы перейдем к установке необходимых пакетов.
Установка библиотек
Нам потребуется всего один пакет:
- react-markdown: поскольку посты будут писаться в Markdown, этот пакет займется отрисовкой кода Mardown и его заменой на HTML.
Выполните в терминале:
Далее займемся отображением списка постов на веб-странице.
Отображение данных
Импортируйте в /pages/index.js
созданную ранее переменную url
:
Теперь добавьте в конец этого файла следующий код:
export const getStaticProps = async () => {
const data = await fetch(`${url}/articles`);
const list = await data.json();
return {
props: {
list,
},
revalidate: 1,
};
};
- строка 1: метод
getStaticProps
дает Next.js команду применить статическую генерацию для получения данных из CMS; - строки 2–3: получение списка статей и преобразование этих данных в JSON;
- строка 6: экспорт списка в виде пропсов.
- строка 9: свойство
revalidate
сообщает Next.js, сколько времени нужно ожидать перед повторной генерацией страницы. В данном случае мы будем выполнять повторную генерацию каждую секунду.
Теперь найдите в /pages/index.js
следующий код:
Измените его на:
Эта строка позволяет внести пропс list
в компонент Home
.
Далее найдите в pages/index.js
блок return
:
Замените его следующим:
return (
<div>
<Head>
<title>Home</title>
</Head>
<h1>Welcome home!</h1>
<ul>
{list.map((item) => (
<li key={item.id}>
<Link href={`/article/${item.id}`}>
<a>{item.Title}</a>
</Link>
</li>
))}
</ul>
</div>
);
- строка 8: используем
map
для получения всех элементов массиваlist
. - строка 10: при клике каждый элемент будет указывать на URL
/article/$id
, где$id
является ID элемента массива. Кроме того, на этом шаге реализуется динамическая маршрутизация. - строка 11: отображаем только поле
Title
элементов.
Выполните код. Ожидаемый результат:
Здорово! Код работает. Дополнительно проверим его, добавив еще один пост. Для этого перейдите обратно в панель Admin и добавьте запись в коллекцию “Article”:
После публикации обновите страницу. Результат должен получиться такой:
Как видите, теперь можно генерировать новые посты без дополнительного написания кода.
В итоге файл /pages/index.js
должен выглядеть так:
import Head from "next/head";
import { url } from "../config/next.config";
import Link from "next/link";
export default function Home({ list }) {
console.log(list);
return (
<div>
<Head>
<title>Home</title>
</Head>
<h1>Welcome home!</h1>
<ul>
{list.map((item) => (
<li key={item.id}>
<Link href={`/article/${item.id}`}>
<a>{item.Title}</a>
</Link>
</li>
))}
</ul>
</div>
);
}
export const getStaticProps = async () => {
const data = await fetch(`${url}/articles`);
const list = await data.json();
return {
props: { list },
revalidate: 1,
};
};
Просмотр статьи
До этого мы реализовали динамическую маршрутизацию. При нажатии по любому элементу он будет перенаправлять на страницу /article/$id
. Осталось только обработать этот URL.
Создайте в директории /pages
каталог article
, а в нем файл [id].js
.
В этом файле пропишите следующий код:
Выполните код. Ожидаемый результат:
Теперь поработаем над извлечением и отображением содержимого постов.
Импортируйте в /pages/article/[id].js
переменную url
и пакет ReactMarkdown
:
Далее пропишите в конце файла следующий код:
export const getStaticProps = async (context) => {
const data = await fetch(`${url}/articles/${context.params.id}`);
const article = await data.json();
return {
props: { article },
revalidate: 1,
};
};
export async function getStaticPaths() {
const res = await fetch(`${url}/articles`);
const articles = await res.json();
const paths = articles.map((item) => ({
params: { id: item.id.toString() },
}));
return { paths, fallback: false };
}
- Строка 1: используем статическую генерацию для получения данных. Переменная
context
позволяет извлечь параметры, находящиеся в URL. - Строки 2–3: получаем данные статьи согласно представленному URL. Например, если пользователь находится на
/article/3
, выполняем запрос на получение статьи сid
равным3
. - Строка 6: возвращаем данные статьи в качестве пропсов.
- Строка 7: просим Next.js выполнять инкрементную генерацию сайта каждую секунду.
- Строка 9: используем
getStaticPaths
для статической генерации путей. - Строка 13: сохраняем все поля
id
каждого элемента в отдельном массиве. - Строка 17: возвращаем список всех путей, которые Next.js нужно сгенерировать. Свойство
fallback
говорит Next.js отображать ошибку 404, если пользователь переходит по несуществующему пути.
После экспорта всех данных статьи нужно их отобразить. Найдите в /pages/article/[id].js
следующий фрагмент кода:
Измените его так:
Далее найдите блок return
:
Замените его на:
- Строка 3: отображаем
Title
в элементе заголовка. - Строка 4: отображаем тело с помощью компонента
ReactMarkdown
. Он будет отрисовывать код Markdown и преобразовывать его в HTML.
Выполните код. Ожидаемый результат:
Как видите, содержимое статьи успешно выводится, и все работает по плану.
В итоге файл /pages/article/[id].js
должен выглядеть так:
import { url } from "../../config/next.config";
import ReactMarkdown from "react-markdown";
export default function Article({ article }) {
return (
<div>
<h1>{article.Title}</h1>
<ReactMarkdown>{article.Body}</ReactMarkdown>
</div>
);
}
export const getStaticProps = async (context) => {
const data = await fetch(`${url}/articles/${context.params.id}`);
const article = await data.json();
return {
props: { article },
revalidate: 1,
};
};
export async function getStaticPaths() {
// Вызываем внешнюю конечную точку API для получения постов
const res = await fetch(`${url}/articles`);
const articles = await res.json();
// Получаем на основе постов пути, которые нужно предварительно отрисовать
const paths = articles.map((item) => ({
params: { id: item.id.toString() },
}));
// В процессе сборки мы будем предварительно отрисовывать только эти пути
// { fallback: false } means other routes should 404.
return { paths, fallback: false };
}
Следующим этапом мы проработаем отображение страницы About Me.
Страница About Me
Этот процесс весьма прост. Создайте в каталоге /pages
файл about.js
.
В этом файле пропишите:
import { url } from "../config/next.config";
export default function About({ data }) {
console.log(data);
return (
<div>
<h1>About the author:</h1>
{data.Body}
</div>
);
}
export const getStaticProps = async () => {
const res = await fetch(`${url}/about-me`);
const data = await res.json();
return {
props: { data },
revalidate: 1,
};
};
- Строка 1: импортируем переменную
url
, указывающую на расположение экземпляра Strapi. - Строка 2: создаем функциональный компонент React. При этом также вносим пропс
data
. - Строка 8: отображаем поле
Body
объектаdata
. - Строки 13–21: используем статическую генерацию для получения соответствующих данных. Позже экспортируем эти данные в качестве пропсов.
Теперь перейдите к localhost:3000/about
. Ожидаемый вывод:
Все отлично работает!
Вот репозиторий этого проекта на GitHub.
Заключение
С появлением CMS, подобных Strapi, жизнь блогеров существенно упростилась. Главным образом благодаря тому, что они избавляют автора от необходимости копаться в коде для внесения в посты простых исправлений. Кроме того, CMS совместно с прекрасными фронтенд-инструментами вроде Next.js оказываются идеальным способом организовать блог в короткий промежуток времени.
Благодарю вас за внимание!
Читайте также:
- 10 видов шаблонного кода на NextJS
- Установка Next.js с использованием клиентского сервера Express и TypeScript
- Познай прокси-объект JavaScript как самого себя
Читайте нас в Telegram, VK и Яндекс.Дзен
Перевод статьи Hussain Arif: Build Your Personal Blog With Next.js and Strapi