/gatsby-contentful-example

ToDo: пройти по руководству А.Товмача и развернуть с Contentful [Gatsby + Contentful + Netlify]

Primary LanguageCSSMIT LicenseMIT

JAMstack: Как создать свой блог используя Gatsby + Contentful + Netlify

🇷🇺 Статья на Хабре
🇺🇦 Статья на DOU

Вы уже слышали о новом подходе JAMstack? Возможность писать веб-приложения на любимом фреймворке, управлять контентом из админ панели, а на выходе получать полностью валидные HTML-страницы построенные согласно с самыми последними рекомендациями SEO, PWA и a11y.

Интересно? Тогда вот список рассматриваемых вопросов в этой статье:

  • Что это за новый стек и зачем он нужен?
  • Как запустить базовое приложение используя Gatsby?
  • Работа с Contentful и создание первой порции данных
  • Как связать Contentful и Gatsby используя GraphQL?
  • Настроить автоматический деплоймент используя Netlify

JAMstack

Как известно: “Всё новое это давно забытое старое” и вот очередное подтверждение ― мода на статические сайты возвращается. Что представлял собой интернет десять лет назад? Это был PHP сервер-рендеринг, который подставлял данные из БД в HTML-шаблоны и отправлял на клиент.

server rendering

На смену этому подходу пришли JavaScript фреймворки, которые в последние годы представлены святой троицей веба React Angular Vue Аминь. В чем было кардинальное отличие? В скорости и отзывчивости интерфейса, ведь теперь вся логика сайта находилась на клиенте, и на любое движение мышью можно вызывать красивую анимацию с изменением контента, отправкой запросов на API.

client rendering

Что дальше? JAM предлагает:

  • никакого server-side рендеринга, да и вообще убрать сервер как таковой
  • никакого client-side рендеринга, долой <div id=”root”></div>
  • компилировать сайт в обычный HTML код, единожды, в момент изменения контента
  • размещение сайта на любом файловом хостинге

JAM

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

Инструментарий

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

hammer nail

Список лучших инструментов на 2019 год:

Gatsby ― это генератор статических сайтов из React + GraphQL приложений. Почему именно такой выбор, а не Angular или Vue я затрудняюсь ответить, но скорее всего дело в злой статистике, которая говорит что не смотря на все споры, React самый популярный фреймворк последних трех лет (не забросайте меня камнями в комментариях, за это утверждение, на самом деле мне заплатили). Для более наглядного представления create-react-app компилирует код в JavaScript билд, для дальнейшего рендера при запуске страницы, Gatsby генерирует полноценные HTML-страницы, с валидной версткой, которые показываются как есть, даже с выключенным JS.

Contentful ― система управления контентом на статических страницах. Это WordPress, который не сохраняет связи между шаблонами и данными в БД, а вместо этого меняет данные непосредственно в HTML файлах.

Netlify ― это очень простая в использовании система деплоймента, которая позволяет связать большинство популярных файловых хостингов с JAM приложением, да ещё и на HTTPS протоколе.

От теории к практике

Теперь когда определились с инструментами ― можно приступать.

Contentful

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

Система управления контентом базируется на двух сущностях ― Content model, описывающая структуру и типы данных, и непосредственно Content. Для начала создадим простую модель для нашего блога. Content model состоит из типов данных, например для блога типами данных будут: Article, Person.

конечно же можно выбрать любой уровень абстракции, который по душе, например можно упразднить Person и указывать данные об авторе внутри Article, как Article.author_name

Структура моей модели
article/
├── title (Short text)
├── text (Long text)
├── banner (Single media)
└── publishedAt (Date & Time)

person/
├── fullName (Short text)
└── avatar (Single media)

Далее, используя уже созданные типы данных, добавляем контент, для текстов можно использовать SaganIpsum для картинок Unsplash.

contentful add content

Gatsby

Открываем терминал и создаем рабочую среду

## Установка
npm install --global gatsby-cli

## Создание проекта
gatsby new personal-blog

## Для любителей минимализма можно установить Hello World проект
## gatsby new minimal-gatsby https://github.com/gatsbyjs/gatsby-starter-hello-world

## Переходим в папку
cd personal-blog
Структура проекта
personal-blog/
├── gatsby-browser.js
├── gatsby-config.js
├── gatsby-node.js
├── gatsby-ssr.js
├── LICENSE
├── node_modules
├── package.json
├── README.md
└── src
    ├── components
    │   ├── header.js
    │   ├── image.js
    │   ├── layout.css
    │   ├── layout.js
    │   └── seo.js
    ├── images
    │   ├── gatsby-astronaut.png
    │   └── gatsby-icon.png
    └── pages
        ├── 404.js
        ├── index.js
        └── page-2.js
## Запуск проекта с hot-reloading
gatsby develop

Что получилось? React + GraphQL приложение собираемое с помощью Gatsby, что значит что можно любой старый проект, который долго рендерится перевести в статический HTML сайт и получить прирост в скорости в несколько раз.

Gatsby+Contentful

## Установка дополнительных пакетов
npm install gatsby-source-contentful dotenv

Создаем файл .env в корне приложения со следующим содержимым:

/* 12-и значный ключ из Contentful → Settings → API keys → Example key 1→ Space ID */
CONTENTFUL_SPACE_ID=xxxxxxxxxxxx
/* 64-х значный ключ из Contentful → Settings → API keys → Example key 1→ Content Delivery API - access token */
CONTENTFUL_ACCESS_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Расширяем конфигурацию в gatsby-config.js:

if (process.env.NODE_ENV === "development") {
  require("dotenv").config();
}
module.exports = {
  /* other settings */
  plugins: [
    /* other plugins */
    {
      resolve: `gatsby-source-contentful`,
      options: {
        spaceId: process.env.CONTENTFUL_SPACE_ID,
        accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,
      },
    }
  ]
}

Перезапускаем Gatsby сервер и если консоль не показывает никаких ошибок, значит соединение с Contentful установлено и можно переходить дальше.

Gatsby+GraphQL+Contentful

Если Вы еще не знакомы с GraphQL, то не переживайте потому что это достаточно просто. Наш сайт сейчас находится по адресу:

http://localhost:8000/

Но мы пока что оставим его и откроем вторую вкладку:

http://localhost:8000/___graphql

Перед нами IDE для GraphQL прямо в браузере. С ним очень удобно строить запросы и тестировать их. Кликните на Docs в верхнем правом углу, чтобы развернуть сайдбар с документацией, но сюрприз, это не документация к GraphQL, это документация Вашего API. Разверните список Query чтобы увидеть все доступные схемы для запросов, с их типами данных.

Интересующие нас схемы имеют примерно следующее название:

contentfulВашТипДанных - один экземпляр
allContentfulВашТипДанных - список экземпляров

Пример моих данных
  • contentfulArticle
  • contentfulPerson
  • allContentfulArticle
  • allContentfulPerson

Используя левую панель построим правильный запрос для наших данных (попробуйте автодополнение, очень удобно).

Пример запрашивающий один экземпляр типа Person и список из Article
{
  contentfulPerson {
    fullName
    avatar {
      file {
        url
      }
    }
  } 
  allContentfulArticle {
    edges {
      node {
        title
        text {
          text
        }
        banner {
          file {
            url
          }
        }
        publishedAt
      }
    }
  }
}

Что можно отметить из структуры запросов:

  • чтобы получить URL для файла, нужно обращаться по пути typeName.file.url
  • чтобы получить текст из типа Long text, идем по пути typeName.typeName
  • чтобы получить список экземпляров какого-то типа нужно использовать следующий путь allContentfulName.edges

Переносим схему запроса в проект и рендерим их как обычные данные в React-приложении. Общепринятым Best Practice считается использование <StaticQuery /> компонента из пакета gatsby, который уже установлен в проект.

Пример файла index.js
import React from "react"
import { StaticQuery, graphql } from "gatsby"

import Layout from "../components/layout"
import Article from "../components/article"

const IndexPage = () => (
  <Layout>
    <StaticQuery
      query={graphql`
        {
          allContentfulArticle {
            edges {
              node {
                id
                title
                text {
                  text
                }
                banner {
                  file {
                    url
                  }
                }
                publishedAt
              }
            }
          }
        }
      `}
      render={({
        allContentfulArticle: {
          edges
        }
      }) => (
        edges.map(({ node }) => (
          <Article key={node.id} content={node} />
        ))
      )}
    />
  </Layout>
)

export default IndexPage

Как это работает? В query передается схема запроса GraphQL, а в render наш любимый JSX. Используйте деструктуризацию чтобы сделать код более читабельным.

Деструктуризация на примере components/article.js
import React from "react"

const Article = ({
  content: {
    title,
    text,
    banner: {
      file: {
        url
      }
    },
    publishedAt
  }
}) => (
  <div>
    <h2>{title}</h2>
    <img src={url} alt={title}/>
    <p>
      {text}
    </p>
    <h5>{publishedAt}</h5>
  </div>
)

export default Article
Теперь когда стало ясно как получить и отрендерить данные можно приступать к разработке, но так как эта статья не о том как сделать сайт на реакте, то мы опустим этот момент и представим что сайт готов.

Разместим наш проект на GitHub, откуда его можно будет деплоить в следующем шаге.

Для тех кто до сих пор не в курсе как это сделать
## Находясь в папке с проектом инициализируем пустой репозиторий
git init

## Сделаем первый коммит
git add .
git commit -m “initial commit”

## Создаем репозиторий на GitHub и подключаем
git remote add origin git@github.com:yourname/my-repository-name.git

## Публикуем изменения
git push origin master

Настраиваем Netlify

Создаем аккаунт используя тот сервис, на котором планируется размещение проектов. Я выбрал GitHub, поэтому после успешной авторизации настроим новый проект, клик на New site from Git. Подключаем наш репозиторий, а Netlify автоматически определит что это Gatsby проект и настроит все скрипты для сборки.

Выбираем нужную ветку, и не забываем про переменные окружения, для этого раскрываем меню Advanced settings и добавляем содержимое локального файла .env и подтверждаем настройки.

Пара минут магии и сайт на месте:
https://tender-liskov-ce3ad0.netlify.com

Осталось добавить хук на обновление контента. Переходим в настройки:

Deploy settings → Build hooks → Add build hook netlify webhook Устанавливаем любое понятное название, для примера "Contentful hook", выбираем ветку с которой будем делать билд и подтверждаем. Результатом будет ссылка, копируем и идем в панель Contentful:

Settings → Webhooks
contentful webhook Ищем на правой боковой панели темплейт для Netlify и в два клика связываем две системы. Пробуем изменить контент и смотрим как новые данные появляются на сайте.

Итого

JAM-stack совмещает в себе решение проблем предшествующих подходов и похоже претендует на захват власти и всемирную популярность, но революция ли это? Ничего нового и особенного нет, но это самая передовая методология последних двух лет, там, на чужбине, а у нас? Мы только-только начали переводить проекты с WordPress на React и это однозначно прогресс, но может чтобы не остаться за бортом, как легендарный индийский аутсорс, нам пора делать более решительные шаги?