javascript

Разработка статического блога на Gatsby и Strapi

  • пятница, 2 февраля 2018 г. в 03:13:11
https://habrahabr.ru/company/ruvds/blog/348068/
  • Разработка веб-сайтов
  • JavaScript
  • Блог компании RUVDS.com


Статические веб-сайты содержат страницы с неизменным содержимым. Технически — это набор HTML-файлов, которые, для каждого посетителя сайта, выглядят одинаково. В отличие от динамических веб-сайтов, для разработки таких сайтов не нужно серверное программирование или базы данных. Публикация статического веб-сайта проста: файлы выгружают на обыкновенный веб-сервер или в некое хранилище. Два основных преимущества статических веб-сайтов — это безопасность и скорость. Тут нет базы данных, поэтому отсюда нечего красть, и тут нет нужды программно генерировать страницу для каждого запроса, что ускоряет работу.

Для того чтобы упростить создание статических веб-сайтов, создано множество опенсорсных инструментов. Например, это Jekyll, Hugo, Hexo, и другие. Работа по подготовке содержимого сайта ведётся путём редактирования чего-то вроде файлов с разметкой, или через некое API для управления контентом. После того, как данные готовы к публикации, генератор берёт эти данные, внедряет их в шаблоны и создаёт множество HTML-файлов, готовых для публикации.

Сегодня мы расскажем о быстрой разработке проектов с помощью Gatsby — генератора статических прогрессивных веб-приложений, и Strapi — системы управления контентом. В результате после того, как вы освоите это руководство, у вас будет работающий статический блог и масса идей, касающихся его развития.

Статические веб-сайты и прогрессивные веб-приложения


Полагаем, прежде чем продолжать, стоит сказать пару слов о прогрессивных веб-приложениях (Progressive Web Apps, PWA). Это — веб-приложения, интенсивно использующие JavaScript, которые отличаются надёжностью, быстротой и привлекательным внешним видом. PWA, благодаря обеспечиваемой ими скорости работы со страницами, и тому, что пользователям удобно с ними взаимодействовать, стали стандартным способом построения веб-интерфейсов. В результате появилось множество фронтенд-фреймворков, таких, как Angular, Vue, и React.

Мы, зная о плюсах статических веб-сайтов и PWA, задались идеей найти способ использовать одновременно и то и другое. Инструмент, который это позволяет, называется Gatsby.

Что такое Gatsby?


Gatsby — это невероятно быстрый фреймворк для разработки веб-сайтов на React. Он позволяет создавать сайты, основанные на React буквально за считанные минуты. Gatsby подходит для проектов разных масштабов — от блогов до корпоративных веб-сайтов.

Так как проекты, созданные с помощью Gatsby, основаны на React, их страницы, при взаимодействии с ними пользователя, не перезагружаются, что делает такие проекты очень быстрыми. Gatsby поддерживает большой набор плагинов, которые позволяют, в частности, использовать данные из различных источников (это, например, markdown-файлы, различные системы управления контентом, и так далее). Центром системы данных Gatsby является интерфейс «узлов», которые используются для моделирования данных, поступающих в Gatsby.

Этот проект создал Кайл Мэтьюз, он официально выпущен в июле 2017-го и уже используется десятками компаний.

Как уже стало понятно, Gatsby, для того, чтобы он мог генерировать HTML-файлы, нужно откуда-то брать данные для них. В нашем случае источником данных будет Strapi.

Что такое Strapi?


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


Strapi имеет расширяемую систему плагинов, он отличается большим набором встроенных возможностей. Среди них — панель администратора, система управления аутентификацией и разрешениями, средства управления контентом, генератор API и так далее.

Strapi — это опенсорсный проект, что выгодно отличает его от других CMS. В частности, это означает, что, во-первых, он полностью бесплатен, а во-вторых — то, что компания, выбравшая Strapi, разворачивает CMS на собственных серверах, то есть данные компании остаются под её полным контролем. Кроме того, Strapi можно настраивать и расширять благодаря системе плагинов.

Описав наши инструменты, приступим к разработке статического блога.

Настройка API с помощью Strapi


Воспользуемся возможностями Strapi для разработки API и добавим в систему данные, которые позже превратятся в страницы блога.

▍Установка Strapi


Для работы Strapi нужны Node 8 (или выше) и MongoDB. Если в вашей системе всё это имеется, можно приступать к установке Strapi с использованием npm:

$ npm i strapi@alpha -g

Обратите внимание на то, что Strapi v3 всё ещё находится на стадии альфа-версии, но нам это подойдёт.

▍Создание проекта Strapi


Создадим директорию gatsby-strapi-tutorial:

$ mkdir gatsby-strapi-tutorial

Создадим каркас API внутри этой директории, для чего сначала перейдём в эту директорию, а потом выполним там соответствующую команду Strapi:

$ cd gatsby-strapi-tutorial
$ strapi new api

▍Запуск сервера


Для запуска сервера Strapi сначала перейдём в соответствующую подпапку директории проекта:

$ cd api

Затем запустим сервер, основанный на Node.js:

$ strapi start

Теперь, если всё сделано правильно, можно будет посетить панель администрирования проекта, которая расположена по адресу http://localhost:1337/admin.

▍Создание первого пользователя


Добавим первого пользователя со страницы регистрации.


▍Создание типа контента


API Strapi основано на структурах данных, которые называются типами контента (Content Type). Это — эквивалент моделей во фреймворках и типов контента в WordPress.

Создадим тип контента с именем article и с тремя полями: title (тип string), content (тип text), и author (тип relation, у одного автора может быть несколько статей).



▍Добавление материалов статей


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

  1. Посетите страницу списка статей.
  2. Щёлкните Add New Article.
  3. Введите данные, ссылку на автора, и отправьте форму.

Создайте, пользуясь тем же подходом, ещё две статьи.


▍Настройка доступа


Из соображений безопасности доступ к API, по умолчанию, ограничен. Для того чтобы открыть доступ, посетите раздел аутентификации и разрешений для роли Guest, выберите действие Article - find и сохраните изменения. С этого момента у вас должна появиться возможность запрашивать список статей.

Доступ к API автора так же ограничен. Разрешите анонимный доступ, выбрав действие find (в разделе Users & Permissions) и сохранив изменения.


Разработка статического веб-сайта


Теперь, когда API готово, можно приступать к разработке статического веб-сайта.

▍Установка Gatsby и создание проекта


Установим Gatsby CLI следующей командой:

$ npm install --global gatsby-cli

В ранее созданной папке gatsby-strapi-tutorial создадим новый блог:

$ gatsby new blog

▍Запуск сервера Gatsby в режиме разработки


Перейдём в папку проекта:

$ cd blog

Запустим сервер:

$ gatsby develop

После этого посмотреть веб-сайт, созданный Gatsby, можно будет, перейдя по адресу http://localhost:8000/.

▍Установка плагина для работы с источником данных Strapi


Данные, которые являются основой статического сайта, могут поступать из разных источников. Например, это markdown-файлы, CSV-файлы, материалы из WordPress (работа с которыми возможна благодаря плагину JSON REST API), и так далее.

Для того чтобы Gatsby успешно делал свою работу, ему нужно уметь общаться с различными источниками данных. Поэтому у Gatsby существует особый слой — слой данных, основанный на GraphQL.

Для того, чтобы подключить Gatsby к источнику данных, требуется плагин, предназначенный для работы с этим источником данных. Такой плагин можно разработать самостоятельно, либо подобрать из уже существующих. В этом примере мы, в качестве источника данных, будем использовать Strapi, а значит, нам понадобится плагин источника данных для API, построенных с помощью Strapi. Мы уже разработали такой плагин.

Установим его:

$ npm install --save gatsby-source-strapi

Этот плагин нуждается в некоторой настройке. Замените содержимое файла gatsby-config.js на следующее:

module.exports = {  
  siteMetadata: {
    title: `Gatsby Default Starter`,
  },
  plugins: [
    `gatsby-plugin-react-helmet`,
    {
      resolve: `gatsby-source-strapi`,
      options: {
        apiURL: `http://localhost:1337`,
        contentTypes: [ // Список типов контента, которые планируется запрашивать из Gatsby.
          `article`,
          `user`
        ]
      },
    },
  ],
}

Теперь перезапустите сервер для того, чтобы позволить Gatsby воспринять изменения.

▍Список статей


Для начала нам хочется вывести список статей. Для того чтобы это сделать, добавьте следующее содержимое в существующий файл домашней страницы src/pages/index.js:

import React from 'react'  
import Link from 'gatsby-link'
const IndexPage = ({ data }) => (  
  <div>
    <h1>Hi people</h1>
    <p>Welcome to your new Gatsby site.</p>
    <p>Now go build something great.</p>
    <ul>
      {data.allStrapiArticle.edges.map(document => (
        <li key={document.node.id}>
          <h2><font color="#3AC1EF">
            <Link to={`/${document.node.id}`}>{document.node.title}</Link>
          </font></h2>
          <p>{document.node.content}</p>
        </li>
      ))}
    </ul>
    <Link to="/page-2/">Go to page 2</Link>
  </div>
)
export default IndexPage
export const pageQuery = graphql`  
  query IndexQuery {
    allStrapiArticle {
      edges {
        node {
          id
          title
          content
        }
      }
    }
  }
`

В конце файла мы экспортируем pageQuery — запрос GraphQL, который позволяет получить полный список статей. Как видите, нам нужны лишь поля id, title и content, и GraphQL позволяет получить именно то, что нам нужно.

Затем мы передаём деструктурированный объект { data } как параметр IndexPage и, для получения выводимых данных, перебираем его поле allStrapiArticles.


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

▍Страница просмотра статьи


Теперь то, что мы делаем, уже похоже на блог, и это хорошо. Однако одной важной вещи всё ещё не хватает: страницы просмотра статьи.

Создадим шаблон, содержащий запрос GraphQL и зададим отображаемое содержимое. Делать это будем в файле src/templates/article.js:

import React from 'react'  
import Link from 'gatsby-link'
const ArticleTemplate = ({ data }) => (  
  <div>
    <h1>{data.strapiArticle.title}</h1>
    <p>by <Link to={`/authors/${data.strapiArticle.author.id}`}>{data.strapiArticle.author.username}</Link></p>
    <p>{data.strapiArticle.content}</p>
  </div>
)
export default ArticleTemplate
export const query = graphql`  
  query ArticleTemplate($id: String!) {
    strapiArticle(id: {eq: $id}) {
      title
      content
      author {
        id
        username
      }
    }
  }
`

Смотрится хорошо, но в данный момент Gatsby не знает, когда нужно выводить этот шаблон. Для каждой статьи нужен собственный URL. Сообщим Gatsby о новых URL с помощью функции createPage.

Для того чтобы это сделать, создадим новую функцию, которая называется makeRequest и используется для выполнения запроса GraphQL. Затем мы экспортируем функцию, которая называется createPage, в которой мы получаем список статей и создаём страницу для каждой из них. Делается это всё в файле gatsby-node.js. Вот что у нас получилось:

const path = require(`path`);
const makeRequest = (graphql, request) => new Promise((resolve, reject) => {  
  // Запрос для получения данных, используемых при создании страниц.
  resolve(
    graphql(request).then(result => {
      if (result.errors) {
        reject(result.errors)
      }
      return result;
    })
  )
});
// Реализация функции Gatsby API "createPages". Она вызывается один раз когда 
// уровень данных готовится к работе для того, чтобы позволить плагину создать из этих данных страницы
exports.createPages = ({ boundActionCreators, graphql }) => {  
  const { createPage } = boundActionCreators;
  const getArticles = makeRequest(graphql, `
    {
      allStrapiArticle {
        edges {
          node {
            id
          }
        }
      }
    }
    `).then(result => {
    // Создаём страницы для каждой статьи
    result.data.allStrapiArticle.edges.forEach(({ node }) => {
      createPage({
        path: `/${node.id}`,
        component: path.resolve(`src/templates/article.js`),
        context: {
          id: node.id,
        },
      })
    })
  });
  // Запрашиваем материалы статей для использования при создании страниц.
  return getArticles;
};

Перезапустите сервер Gatsby. Теперь ссылки на статьи должны оказаться рабочими, щелчки по ним будут открывать страницы статей.


▍Страница автора


Статьи пишут авторы. Они заслуживают отдельной страницы. Процесс по созданию страницы автора очень похож на процесс создания страницы статьи. Для начала создадим шаблон в файле src/templates/user.js:

import React from 'react'  
import Link from 'gatsby-link'
const UserTemplate = ({ data }) => (  
  <div>
    <h1>{data.strapiUser.username}</h1>
    <ul>
      {data.strapiUser.articles.map(article => (
        <li key={article.id}>
          <h2><font color="#3AC1EF">
            <Link to={`/${article.id}`}>{article.title}</Link>
          </font></h2>
          <p>{article.content}</p>
        </li>
      ))}
    </ul>
  </div>
)
export default UserTemplate
export const query = graphql`  
  query UserTemplate($id: String!) {
    strapiUser(id: { eq: $id }) {
      id
      username
      articles {
        id
        title
        content
      }
    }
  }
`

Теперь обновим файл gatsby-node.js для создания соответствующих ссылок:

const path = require(`path`);
const makeRequest = (graphql, request) => new Promise((resolve, reject) => {  
  // Запрос для получения данных, используемых при создании страниц.
  resolve(
    graphql(request).then(result => {
      if (result.errors) {
        reject(result.errors)
      }
      return result;
    })
  )
});

// Реализация функции Gatsby API "createPages". Она вызывается один раз когда 
// уровень данных готовится к работе для того, чтобы позволить плагину создать из этих данных страницы
exports.createPages = ({ boundActionCreators, graphql }) => {  
  const { createPage } = boundActionCreators;
  const getArticles = makeRequest(graphql, `
    {
      allStrapiArticle {
        edges {
          node {
            id
          }
        }
      }
    }
    `).then(result => {
    // Создаём страницы для каждой статьи.
    result.data.allStrapiArticle.edges.forEach(({ node }) => {
      createPage({
        path: `/${node.id}`,
        component: path.resolve(`src/templates/article.js`),
        context: {
          id: node.id,
        },
      })
    })
  });
  const getAuthors = makeRequest(graphql, `
    {
      allStrapiUser {
        edges {
          node {
            id
          }
        }
      }
    }
    `).then(result => {
    // Создаём страницы для каждого пользователя.
    result.data.allStrapiUser.edges.forEach(({ node }) => {
      createPage({
        path: `/authors/${node.id}`,
        component: path.resolve(`src/templates/user.js`),
        context: {
          id: node.id,
        },
      })
    })
  });
  // Запросы материалов статей и данных авторов для использования при создании страниц.
  return Promise.all([
    getArticles,
    getAuthors,
  ])
};

И наконец, перезагрузим сервер и посетим страницу автора, перейдя на неё со страницы просмотра статьи по соответствующей ссылке.


Итоги


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

Что делать дальше?

Вы вполне можете продолжить работу над этим проектом для того, чтобы изучить полезные возможности Gatsby и Strapi. Сюда можно добавить список авторов, категории статей, систему комментирования на базе Strapi API или Disqus. Кроме того, вы можете, пользуясь предложенной здесь методикой, создавать и другие веб-сайты (интернет-магазины, корпоративные сайты, и так далее).

Когда ваш проект будет готов к работе, вы, возможно, захотите выложить его в интернет. Веб-проекты, сгенерированные Gatsby, можно публиковать, пользуясь средствами сервисов для размещения статических сайтов, таких, как Netlify, S3/Cloudfront, страницы GitHub, страницы GitLab, Heroku, и так далее. API Strapi — это система, основанная на Node.js, поэтому оно может быть развёрнуто на базе Heroku или с используемой любой виртуальной машины Linux с установленным на ней Node.js.

Полную версию кода, который мы тут разбирали, можно найти на GitHub. Для того, чтобы увидеть то, что тут создано, в действии, клонируйте репозиторий, выполните команду npm run setup, запустите сервер Strapi (перейдите в папку api и выполните команду strapi start) и сервер Gatsby (перейдите в папку blog и выполните команду npm run develop).

Уважаемые читатели! Как вы создаёте статические веб-сайты? Планируете ли вы использовать связку Gatsby-Strapi в своих проектах?