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
, у одного автора может быть несколько статей).
▍Добавление материалов статей
Добавим в базу данных несколько статей. Для того чтобы создать статью, выполните следующую последовательность действий:
- Посетите страницу списка статей.
- Щёлкните
Add New Article
.
- Введите данные, ссылку на автора, и отправьте форму.
Создайте, пользуясь тем же подходом, ещё две статьи.
▍Настройка доступа
Из соображений безопасности
доступ к 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 в своих проектах?