Создание приложения для блога с помощью Remix и Strapi CMS

В этой статье подробно описаны шаги по созданию приложения для блога с помощью Remix и Strapi CMS.

Автор: Джозеф Чеге

Strapi — это безголовая CMS с открытым исходным кодом, основанная на Node.js. Она позволяет вам разрабатывать и управлять любым содержимым вашего приложения. Это позволяет быстрее создавать бэкенд API с преимуществами эффективности и настраиваемости.

Что такое Remix?

С другой стороны, Remix — это хороший выбор для использования созданных конечных точек API. Он предлагает загрузку данных на стороне сервера. Remix — это фреймворк для рендеринга на стороне сервера. Он позволяет вам работать без проблем с сервером и клиентом. Remix близко сравним с фреймворком Next.js.

Remix vs Next.js

Next.js — один из популярных фреймворков React для рендеринга на стороне сервера. Традиционно приложения React отображаются на стороне клиента. Когда отправляется первоначальный запрос от веб-приложения, браузеру посылается оболочка голой HTML-страницы без предварительного рендеринга. В конце браузер получает файл JavaScript, отвечающий за рендеринг HTML-страницы.

С появлением фреймворков Server-Side Rendering (SSR), таких как Next.js и Remix, страница полностью рендерится на сервере по требованию. Этот подход подходит для динамического контента, который часто меняется.

Некоторые из причин, по которым Remix является хорошим выбором, включают:

  • Он быстрее, чем Next.js.
  • Remix имеет лучшую производительность.
  • Remix использует возможности родного браузера. Это позволяет Remix повторно использовать большинство возможностей HTML и HTTP на уровне платформы для обработки сложных мутаций. С другой стороны, если приложение Next.js перейдет в автономный режим, страница не будет отвечать, что затрудняет обработку мутаций.
  • Remix использует родной HTML и может работать без JavaScript. Это облегчает обработку ошибок на сервере, создавая хорошие впечатления для пользователя.

Remix и Next.js тесно связаны, и разница между ними минимальна. Ознакомьтесь с этим руководством, чтобы получить более полное представление о том, чем Remix отличается от Next.js.

Предварительные условия

Чтобы продолжить эту статью, необходимо иметь следующее:

  • На вашем компьютере установлена среда выполнения Node.js,
  • базовые знания JavaScript, и
  • Предварительный опыт работы с фреймворком на основе React, таким как Remix.

Настройка Strapi локально

Давайте погрузимся в работу и создадим бэкенд Strapi CMS. Он будет обслуживать записи блога для пользователей. Чтобы настроить Strapi CMS, создайте папку проекта. Затем откройте команду, указывающую на эту папку, предпочтительно с помощью текстового редактора, такого как Visual Studio Code. Выполните следующую команду, чтобы установить Strapi CMS на локальном компьютере:

    npx create-strapi-app@latest blog-app
Войти в полноэкранный режим Выйти из полноэкранного режима

Убедитесь, что вы выполнили эту команду в соответствии со следующим типом установки:

В результате будет создана папка blog-app, в которой будут находиться все файлы проекта и зависимости, необходимые Strapi CMS для локального запуска. После завершения установки вы будете перенаправлены на страницу администратора Strapi в вашем браузере по умолчанию по адресу http://localhost:1337/admin/auth/register-admin.

Введите учетные данные для доступа к админке Strapi. Если вы еще не создали учетную запись, укажите данные для входа. Наконец, нажмите кнопку Let’s start, чтобы получить доступ к панели администратора.

Создание коллекции блогов с помощью Strapi CMS

Здесь мы создаем приложение для блога. Поэтому нам нужно смоделировать содержимое бэкенда приложения блога с помощью Strapi. Первым шагом будет настройка типа контента. На панели администратора Strapi нажмите Content-Type Builder.

Затем нажмите кнопку + Создать новый тип коллекции, чтобы настроить коллекцию. Введите blog в качестве имени типа содержимого:

Нажмите кнопку Продолжить и настройте следующие поля блога:

  • Заголовок в виде короткого текста — Краткий заголовок для записи в блоге.
  • Отрывок как длинный текст — краткое содержание вашего сообщения, которое будет отображаться в веб-приложении.
  • Герой: выберите медиа, одиночный — Описательное изображение для вашего сообщения в блоге.
  • Содержание: как насыщенный текст — представляет собой содержание вашего сообщения в блоге.

Наконец, создайте тестовый контент для вышеуказанной коллекции и ее полей. Перейдите вперед и нажмите кнопку + Создать новую запись:

Заполните все поля, а затем обязательно опубликуйте добавленный контент:

Убедитесь, что вы создали как минимум три разных записи в блоге, используя ту же процедуру, что описана выше.

Добавление ролей и разрешений

Strapi CMS имеет разделенную структуру приложения. Чтобы получить доступ к ее содержимому, необходимо установить разрешения и роли, которые определяют, какие данные должны быть открыты для ваших каналов пользователей.

В данном примере нам нужно, чтобы Remix взаимодействовал с созданной нами коллекцией. Таким образом, нам нужно настроить доступ к этой коллекции, чтобы Remix мог выполнить нужный запрос и получить ожидаемые ответы.

Чтобы получить доступ к созданной коллекции blog, создайте API-токен, который Remix будет использовать для взаимодействия со Strapi. Чтобы создать токен:

  • Перейдите в раздел Настройки на панели управления Strapi.
  • Перейдите в раздел API-токены.
  • Нажмите кнопку Create new API Token, чтобы установить токен для использования API.

Заполните имя и описание в соответствующих полях. Наконец, выберите тип токена Read-only и нажмите кнопку сохранить.

В этом примере Remix будет читать только содержимое нашей коллекции. Если вам нужно добавить такие операции, как запись в Strapi CMS, убедитесь, что вы изменили тип токена соответствующим образом.

Будет сгенерирован токен API. Скопируйте созданный токен, так как мы будем использовать его в Remix.

Настройка приложения Remix

Теперь давайте создадим фронтенд-приложение для потребления контента, созданного с помощью Strapi. В каталоге проекта, который вы создали ранее, выполните следующую команду для настройки Remix:

    npx create-remix@latest remix-blog-app
Войти в полноэкранный режим Выйти из полноэкранного режима

Приведенная выше команда создаст папку remix-blog-app, в которой будут находиться все файлы проекта и зависимости, необходимые Remix для запуска локального веб-приложения.

После завершения установки перейдите во вновь созданную директорию:

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

Вы можете проверить, правильно ли работает приложение Remix, запустив его:

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

Откройте http://localhost:3000/ в браузере, и перед вами должна появиться hello world версия веб-приложения Remix.

В корневом каталоге проекта Remix (remix-blog-app) создайте файл .env и добавьте в него следующие конфигурации Remix:

STRAPI_API_TOKEN="your_access_token"
STRAPI_URL_BASE="http://your_local_ip_address:1337"
Войти в полноэкранный режим Выйти из полноэкранного режима

Вставьте свой токен доступа из приборной панели Strapi вместо ваш токен_доступа.

Настройка компонентов Remix

Компоненты задают пользовательский интерфейс приложения. Remix использует компоненты для настройки различных разделов веб-приложения. Здесь будут созданы следующие компоненты:

  • Панель навигации: Основная панель навигации веб-приложения
  • Карточки постов в блоге: Карточки Remix для отображения постов и их свойств
  • Макет: Для установки общего макета веб-страницы

Чтобы установить эти компоненты, создайте папку components в директории app проекта Remix. Внутри папки components создайте следующие файлы и соответствующие блоки кода для создания компонентов:

    export default function Navbar() {
        return (
            <nav className="navbar">
                <div className="nav-wrapper">
                    <a href="/" className="brand-logo">Blog App</a>
                </div>
            </nav>
        )
    }
Вход в полноэкранный режим Выход из полноэкранного режима

Здесь мы создаем Navbar, который отображает логотип бренда приложения в виде текста Blog App. Щелчок на этом логотипе перенаправляет пользователя на главную страницу приложения.

BlogCard.jsx:

    import { Link } from '@remix-run/react';
    import url from '../utils/url';

    export default function BlogCard({ blog }) {
        let data = blog.attributes;
        return (
            <div className="card">
                <div className="card-content">
                    <div className="card-img">
                        <img src={`${url}${data.hero.data.attributes.url}`} alt={data.hero.data.attributes.alternativeText} />
                    </div>
                    <div className="card-details">

                        <Link to={`/posts/${blog.id}`} className="card-title">
                            {data.title}
                        </Link>

                        <p className="card-excerpt">{data.excerpt}</p>
                    </div>
                </div>
            </div>
        )
    }
Вход в полноэкранный режим Выход из полноэкранного режима

Этот BlogCard будет отображать и упорядочивать блоги в вашем приложении. Здесь каждая карточка поста будет отображать заголовок поста, изображение героя и отрывок поста.

Layout.jsx:

    import Navbar from './Navbar';

    export default function Layout({ children }) {
        return (
            <div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
                <Navbar />
                <div className="container">
                    {children}
                </div>
            </div>
        );
    }
Вход в полноэкранный режим Выход из полноэкранного режима

Компонент Layout запускает контейнер, который оборачивает компонент Navbar в основное приложение.

style.css

Чтобы придать стиль вышеуказанным компонентам, добавьте следующий CSS-код в файл style.css:

    /* Navbar */
    .navbar {
      box-shadow: 0 1px 0 rgba(0, 0, 0, 0.05);
      margin-bottom: 0;
      padding: 12px;
      position: relative;
    }

    .navbar .nav-wrapper a {
      text-decoration: none;
      font-size: 20px;
    }

    /* Layout */
    .container {
      width: 50%;
      margin: 0px auto;
    }

    /* Blog card */
    .card {
      width: 100%;
      padding: 10px;
      margin: 10px 0px;
      border-radius: 5px;
      box-shadow: 0 1px 3px 0 #d4d4d5, 0 0 0 1px #d4d4d5;
    }

    .card-content {
      width: 100%;
      display: flex;
      justify-content: space-between;
    }

    .card-content .card-img {
      width: 50%;
      height: 100%;
    }

    .card-img img {
      width: 90%;
      height: 100%;
      border-radius: 5px;
    }

    .card-details .card-title {
      text-decoration: none;
    }
Вход в полноэкранный режим Выход из полноэкранного режима

index.jsx:

Для выполнения вышеуказанных компонентов создайте файл index.jsx и экспортируйте его, как показано в следующем блоке кода:

    import BlogCard from "./BlogCard";
    import Layout from "./Layout";
    import Navbar from "./Navbar";
    export { BlogCard, Layout, Navbar };
Вход в полноэкранный режим Выход из полноэкранного режима

Экспорт этих компонентов облегчает другим модулям приложения доступ к ним и их соответствующее использование.

Настройка утилит Remix

Создайте папку utils внутри каталога Remix app. Внутри папки utils создайте следующие файлы:

    // Custom error class for errors from Strapi API
    class APIResponseError extends Error {
        constructor(response) {
            super(`API Error Response: ${response.status} ${response.statusText}`);
        }
    }

    export const checkStatus = (response) => {
        if (response.ok) {
            // response.status >= 200 && response.status < 300
            return response;
        } else {
            throw new APIResponseError(response);
        }
    }

    class MissingEnvironmentVariable extends Error {
        constructor(name) {
            super(`Missing Environment Variable: The ${name} environment variable must be defined`);
        }
    }

    export const checkEnvVars = () => {
        const envVars = [
            'STRAPI_URL_BASE',
            'STRAPI_API_TOKEN'
        ];

        for (const envVar of envVars) {
            if (!process.env[envVar]) {
                throw new MissingEnvironmentVariable(envVar)
            }
        }
    }
Вход в полноэкранный режим Выход из полноэкранного режима
    export default "http://localhost:1337";
Войти в полноэкранный режим Выход из полноэкранного режима

Настройка маршрутов

Для доступа к постам мы создадим маршруты Remix. В данном случае у нас будет два основных маршрута:

  • Маршрут один для получения всех постов.
  • Маршрут два, который является дочерним маршрутом для каждого поста, чтобы помочь нам получить доступ к отдельному посту.

Давайте создадим эти маршруты.

Выборка всех постов

Перейдите в файл app/routes/index.jsx и найдите все посты блога следующим образом:

  • Импортируйте все необходимые модули:
    import { useLoaderData } from '@remix-run/react';
    import { checkEnvVars, checkStatus } from '../utils/errorHandling';
    import {Layout, BlogCard} from '../components';
    import styles from '../components/style.css';
Войдите в полноэкранный режим Выйти из полноэкранного режима
  • Настройте стили для компонента BlogCard:
export const links = () => [
        { rel: "stylesheet", href: styles },
    ];
Войти в полноэкранный режим Выйти из полноэкранного режима
  • Настройте загрузчик для получения постов из Strapi:
    export async function loader() {
        checkEnvVars(); // check environmental variables
        const response = await fetch(`${process.env.STRAPI_URL_BASE}/api/blogs?populate=hero`, {
            method: "GET",
            headers: {
                "Authorization": `Bearer ${process.env.STRAPI_API_TOKEN}`,
                "Content-Type": "application/json"
            }
        }); // get the blogs

        checkStatus(response); // check the status

        const data = await response.json(); // get the json response

        if (data.error) { // error check
            throw new Response("Error loading data from strapi", { status: 500 });
        }

        return data.data; // return the data
    }
Войти в полноэкранный режим Выйти из полноэкранного режима
  • Отредактируйте функцию рендеринга, чтобы получить посты и отобразить их на компоненте BlogCard:
export default function Index() {
        const blogs = useLoaderData();
        return (
            <Layout>
                {
                    blogs.length > 0 ? (
                        blogs.map(blog => (
                            <BlogCard key={blog.id} blog={blog} />
                        ))
                    ) : (
                        <p>No blog posts found!</p>
                    )
                }
            </Layout>
        );
    }
Войти в полноэкранный режим Выйти из полноэкранного режима

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

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

Это обслужит ваше приложение на http://localhost:3000. Используйте эту ссылку и откройте приложение в браузере. В зависимости от количества добавленных постов, ваша страница должна быть похожа на эту:

Получение одного поста

На данном этапе Remix может обслуживать записи блога. Однако мы не можем получить доступ к содержимому каждого отдельного поста. Для этого:

  • Создайте каталог posts внутри каталога app/routes.
  • Создайте файл $postId.jsx в директории posts.
  • В файле $postId.jsx импортируйте необходимые модули:
    import { useLoaderData } from '@remix-run/react';
    import { checkEnvVars, checkStatus } from '../../utils/errorHandling';
    import url from '../../utils/url';
    import { Layout } from '../../components';
    import styles from '../../components/style.css';
Вход в полноэкранный режим Выход из полноэкранного режима
  • Настройте стили:
    export const links = () => [
        { rel: "stylesheet", href: styles },
    ];
Войти в полноэкранный режим Выйти из полноэкранного режима
  • Настройте функцию загрузчика для получения каждого поста:
    export async function loader({ params }) {
        const { postId } = params; // get the post id
        checkEnvVars(); // check the environmental variables
        const response = await fetch(`${process.env.STRAPI_URL_BASE}/api/blogs/${postId}?populate=hero`, {
            method: "GET",
            headers: {
                "Authorization": `Bearer ${process.env.STRAPI_API_TOKEN}`,
                "Content-Type": "application/json"
            }
        }); // send a request to strapi backend to get the post

        checkStatus(response); // check the response status

        const data = await response.json(); // get the json data

        if (data.error) {// check if we have an error
            throw new Response("Error loading data from strapi", { status: 500 });
        }

        return data.data; // return the data
    }
Войти в полноэкранный режим Выход из полноэкранного режима
  • Настройте функцию рендеринга, чтобы получить данные и отобразить их:
    export default function Post() {
        const blog = useLoaderData();
        const blogData = blog.attributes;
        return (
            <Layout>
                <div className="blog-post">
                    <div className="blog-post-hero">
                        <img src={`${url}${blogData.hero.data.attributes.url}`} alt={`${blogData.hero.data.attributes.alternativeText}`} />
                    </div>
                    <div className="blog-post-title">
                        <h1>{blogData.title}</h1>
                    </div>
                    <div className="blog-post-content">
                        <div dangerouslySetInnerHTML={{ __html: blogData.content }} />
                    </div>
                </div>
            </Layout>
        )
    }
Войти в полноэкранный режим Выход из полноэкранного режима

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

Заключение

Strapi CMS используется для разработки и управления содержимым любого приложения. Она помогает быстрее создавать API и использовать контент через Restful API и GraphQL. В этом руководстве мы создали Strapi Restful API, а затем использовали его для создания минималистичного приложения Remix blog.

Вы можете получить исходный код, использованный в этом проекте, в репозитории GitHub для части Remix Frontend.

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