Упростите свой стек с помощью специального генератора статических сайтов
Опубликовано: 2022-03-10С появлением движения Jamstack статично обслуживаемые сайты снова стали в моде. Большинство разработчиков, обслуживающих статический HTML, не создают собственный HTML. Чтобы получить солидный опыт разработки, мы часто обращаемся к инструментам, называемым генераторами статических сайтов (SSG).
Эти инструменты имеют множество функций, которые делают разработку крупномасштабных статических сайтов приятной. Независимо от того, предоставляют ли они простые подключения к сторонним API, таким как источники данных Gatsby, или предоставляют углубленную настройку, такую как огромная коллекция механизмов шаблонов 11ty, в создании статических сайтов каждый найдет что-то для себя.
Поскольку эти инструменты созданы для различных вариантов использования, они должны иметь множество функций. Эти особенности делают их мощными. Они также делают их довольно сложными и непрозрачными для новых разработчиков. В этой статье мы разберем основные компоненты SSG и создадим свои собственные.
Что такое генератор статических сайтов?
По своей сути генератор статических сайтов представляет собой программу, которая выполняет серию преобразований группы файлов, чтобы преобразовать их в статические ресурсы, такие как HTML. Какие типы файлов он может принимать, как он их преобразует и какие типы файлов выводятся, различают SSG.
Jekyll, ранний и все еще популярный SSG, использует Ruby для преобразования шаблонов Liquid и файлов содержимого Markdown в HTML.
Гэтсби использует React и JSX для преобразования компонентов и контента в HTML. Затем он делает еще один шаг и создает одностраничное приложение, которое можно обслуживать статически.
11ty рендерит HTML из движков шаблонов, таких как Liquid, Handlebars, Nunjucks или литералы шаблонов JavaScript.
Каждая из этих платформ имеет дополнительные функции, облегчающие нашу жизнь. Они предоставляют темы, создают конвейеры, архитектуру плагинов и многое другое. С каждой дополнительной функцией появляется больше сложности, больше волшебства и больше зависимостей. Конечно, это важные функции, но не каждому проекту они нужны.
Между этими тремя разными SSG мы видим еще одну общую тему: данные + шаблоны = конечный сайт. Кажется, это основная функциональность генератора статических сайтов. Это функциональность, на которой мы будем основывать нашу SSG.
По своей сути генератор статических сайтов представляет собой программу, которая выполняет серию преобразований группы файлов, чтобы преобразовать их в статические ресурсы, такие как HTML.
“
Стек технологий нашего нового генератора статических сайтов: Handlebars, Sanity.io и Netlify
Чтобы создать нашу SSG, нам понадобится механизм шаблонов, источник данных и хост, на котором можно запустить нашу SSG и построить наш сайт. Многие генераторы используют Markdown в качестве источника данных, но что, если мы пойдем дальше и нативно подключим нашу SSG к CMS?
- Источник данных: Sanity.io
- Получение данных и создание шаблонов: Node и Handlebars
- Хост и развертывание: Netlify.
Предпосылки
- NodeJS установлен
- Аккаунт Sanity.io
- Знание Git
- Базовые знания командной строки
- Базовые знания о развертывании в таких сервисах, как Netlify.
Примечание . Чтобы продолжить, вы можете найти код в этом репозитории на GitHub.
Настройка структуры нашего документа в HTML
Чтобы начать структуру нашего документа, мы собираемся написать простой HTML. Пока не нужно усложнять.
В структуре нашего проекта нам нужно создать место для наших исходных файлов. В этом случае мы создадим каталог src
и поместим внутрь наш index.html
.
В index.html
мы наметим желаемый контент. Это будет относительно простая страница «О нас».
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Title of the page!</title> </head> <body> <h1>The personal homepage of Bryan Robinson</h1> <p>Some pagraph and rich text content next</p> <h2>Bryan is on the internet</h2> <ul> <li><a href="linkURL">List of links</a></li> </ul> </body> </html>
Давайте не будем усложнять. Мы начнем с h1
для нашей страницы. Далее мы добавим несколько абзацев биографической информации и прикрепим страницу к списку ссылок, чтобы увидеть больше.
Преобразуйте наш HTML в шаблон, который принимает данные
После того, как у нас есть наша базовая структура, нам нужно настроить процесс, чтобы объединить ее с некоторым объемом данных. Для этого мы будем использовать шаблонизатор Handlebars.
По своей сути Handlebars берет HTML-подобную строку, вставляет данные с помощью правил, определенных в документе, а затем выводит скомпилированную HTML-строку.
Чтобы использовать Handlebars, нам нужно инициализировать package.json и установить пакет.
Запустите npm init -y
, чтобы создать структуру файла package.json с некоторым содержимым по умолчанию. Получив это, мы можем установить Handlebars.
npm install handlebars
Наш скрипт сборки будет скриптом Node. Это скрипт, который мы будем использовать локально для сборки, а также то, что наш поставщик развертывания и хост будут использовать для создания нашего HTML-кода для работающего сайта.
Чтобы запустить наш скрипт, мы создадим файл index.js
и потребуем два пакета вверху. Первый — это Handlebars, а второй — модуль по умолчанию в Node для доступа к текущей файловой системе.
const fs = require('fs'); const Handlebars = require('handlebars');
Мы будем использовать модуль fs
для доступа к нашему исходному файлу, а также для записи в файл дистрибутива. Чтобы начать нашу сборку, мы создадим main
функцию для нашего файла, который будет запускаться при вызове, и функцию buildHTML
для объединения наших данных и разметки.
function buildHTML(filename, data) { const source = fs.readFileSync(filename,'utf8').toString(); const template = Handlebars.compile(source); const output = template(data); return output } async function main(src, dist) { const html = buildHTML(src, { "variableData": "This is variable data"}); fs.writeFile(destination, html, function (err) { if (err) return console.log(err); console.log('index.html created'); }); } main('./src/index.html', './dist/index.html');
Функция main()
принимает два аргумента: путь к нашему шаблону HTML и путь, по которому мы хотим, чтобы наш созданный файл жил. В нашей основной функции мы запускаем buildHTML
по исходному пути шаблона с некоторым объемом данных.
Функция сборки преобразует исходный документ в строку и передает эту строку в Handlebars. Handlebars компилирует шаблон, используя эту строку. Затем мы передаем наши данные в скомпилированный шаблон, и Handlebars отображает новую строку HTML, заменяя любые переменные или логику шаблона выходными данными.
Мы возвращаем эту строку в нашу main
функцию и используем метод writeFile
, предоставляемый модулем файловой системы Node, для записи нового файла в указанное нами место, если каталог существует.
Чтобы предотвратить ошибку, добавьте в свой проект каталог dist
с файлом .gitkeep
. Мы не хотим фиксировать наши собранные файлы (наш процесс сборки сделает это), но нам нужно убедиться, что этот каталог есть для нашего скрипта.
Прежде чем мы создадим CMS для управления этой страницей, давайте убедимся, что она работает. Для проверки мы изменим наш HTML-документ, чтобы использовать только что переданные в него данные. Мы будем использовать синтаксис переменной Handlebars для включения содержимого variableData
.
<h1>{{ variableData }}</h1>
Теперь, когда в нашем HTML есть переменная, мы готовы запустить скрипт нашего узла.
node index.js
После завершения скрипта у нас должен быть файл /dist/index.html
. Если мы прочитаем это в браузере, мы увидим нашу разметку, а также нашу строку «Это переменные данные».
Подключение к CMS
У нас есть способ объединения данных с помощью шаблона, теперь нам нужен источник для наших данных. Этот метод будет работать с любым источником данных, имеющим API. Для этой демонстрации мы будем использовать Sanity.io.
Sanity — это первый источник данных API, который обрабатывает контент как структурированные данные. У них есть система управления контентом с открытым исходным кодом, которая делает управление и добавление данных более удобным как для редакторов, так и для разработчиков. CMS часто называют «безголовой» CMS. Вместо традиционной системы управления, в которой ваши данные тесно связаны с вашей презентацией, безголовая CMS создает уровень данных, который может использоваться любым интерфейсом или службой (и, возможно, многими одновременно).
Sanity — платная услуга, но у них есть «Стандартный» план, который является бесплатным и имеет все функции, необходимые для такого сайта.
Настройка здравомыслия
Самый быстрый способ приступить к работе с новым проектом Sanity — использовать интерфейс командной строки Sanity. Мы начнем с глобальной установки.
npm install -g @sanity/cli
CLI дает нам доступ к группе помощников для управления, развертывания и создания. Для начала запустим sanity init
. Это проведет нас через анкету, чтобы помочь запустить нашу студию (то, что Sanity называет своей CMS с открытым исходным кодом).
Select a Project to Use: Create new project HTML CMS Use the default dataset configuration? Y // this creates a "Production" dataset Project output path: studio // or whatever directory you'd like this to live in Select project template Clean project with no predefined schemas
Этот шаг создаст новый проект и набор данных в вашей учетной записи Sanity, создаст локальную версию Studio и свяжет данные и CMS вместе для вас. По умолчанию директория studio
будет создана в корне нашего проекта. В более масштабных проектах вы можете настроить это как отдельный репозиторий. Для этого проекта нормально, чтобы это было связано вместе.
Чтобы запустить нашу студию локально, мы изменим каталог на каталог studio
и запустим sanity start
. Это запустит Studio на localhost:3333
. Когда вы войдете в систему, вам будет представлен экран, сообщающий, что у вас есть «Пустая схема». После этого пришло время добавить нашу схему, именно так наши данные будут структурированы и отредактированы.
Создание схемы здравомыслия
Способ создания документов и полей в Sanity Studio заключается в создании схем в файле schemas/schema.js
.
Для нашего сайта мы создадим тип схемы под названием «О деталях». Наша схема будет вытекать из нашего HTML. В общем, мы могли бы сделать большую часть нашей веб-страницы одним полем с форматированным текстом, но лучше всего структурировать наш контент несвязанным образом. Это обеспечивает большую гибкость в том, как мы можем захотеть использовать эти данные в будущем.
Для нашей веб-страницы нам нужен набор данных, включающий следующее:
- Заголовок
- Полное имя
- Биография (с редактированием форматированного текста)
- Список веб-сайтов с названием и URL.
Чтобы определить это в нашей схеме, мы создаем объект для нашего документа и определяем его поля. Аннотированный список нашего контента с type
поля:
- Заголовок — строка
- Полное имя — строка
- Биография — массив «блоков»
- Список сайтов — массив объектов со строковыми полями имени и URL.
types: schemaTypes.concat([ /* Your types here! */ { title: "About Details", name: "about", type: "document", fields: [ { name: 'title', type: 'string' }, { name: 'fullName', title: 'Full Name', type: 'string' }, { name: 'bio', title: 'Biography', name: 'content', type: 'array', of: [ { type: 'block' } ] }, { name: 'externalLinks', title: 'Social media and external links', type: 'array', of: [ { type: 'object', fields: [ { name: 'text', title: 'Link text', type: 'string' }, { name: 'href', title: 'Link url', type: 'string' } ] } ] } ] } ])
Добавьте это в свои типы схем, сохраните, и ваша Studio перекомпилирует и представит вам ваши первые документы. Отсюда мы добавим наш контент в CMS, создав новый документ и заполнив информацию.
Структурирование вашего контента повторно используемым способом
На этом этапе вам может быть интересно, почему у нас есть «полное имя» и «название». Это потому, что мы хотим, чтобы наш контент мог быть многоцелевым. Включая поле имени вместо того, чтобы включать имя только в заголовок, мы делаем эти данные более полезными. Затем мы можем использовать информацию в этой CMS для создания страницы резюме или PDF. Поле биографии может программно использоваться в других системах или на веб-сайтах. Это позволяет нам иметь единый источник достоверной информации для большей части этого контента, а не диктоваться прямым вариантом использования этого конкретного сайта.
Вытягивание наших данных в наш проект
Теперь, когда мы сделали наши данные доступными через API, давайте добавим их в наш проект.
Установите и настройте клиент Sanity JavaScript
Прежде всего, нам нужен доступ к данным в Node. Мы можем использовать клиент Sanity JavaScript, чтобы установить это соединение.
npm install @sanity/client
Это позволит получить и установить пакет SDK для JavaScript. Отсюда нам нужно настроить его для получения данных из проекта, который мы настроили ранее. Для этого мы настроим служебный скрипт в /utils/SanityClient.js
. Мы предоставляем SDK идентификатор нашего проекта и имя набора данных, и мы готовы использовать его в нашем основном скрипте.
const sanityClient = require('@sanity/client'); const client = sanityClient({ projectId: '4fs6x5jg', dataset: 'production', useCdn: true }) module.exports = client;
Получение наших данных с помощью GROQ
Вернувшись в наш файл index.js
, мы создадим новую функцию для получения наших данных. Для этого мы будем использовать собственный язык запросов Sanity — GROQ с открытым исходным кодом.
Мы создадим запрос в переменной, а затем используем клиент, который мы настроили для получения данных на основе запроса. В этом случае мы создаем объект со свойством about
. В этом объекте мы хотим вернуть данные для нашего конкретного документа. Для этого мы делаем запрос на основе документа _id
, который генерируется автоматически при создании нашего документа.
Чтобы найти _id
документа, мы переходим к документу в Studio и либо копируем его из URL-адреса, либо переходим в режим «Проверка», чтобы просмотреть все данные в документе. Чтобы войти в Inspect, щелкните меню «kabob» в правом верхнем углу или используйте сочетание клавиш Ctrl + Alt + I. В этом представлении будут перечислены все данные этого документа, включая наш _id
. Sanity вернет массив объектов документа, поэтому для простоты мы вернем 0th
-ю запись.
Затем мы передаем запрос методу fetch
нашего клиента Sanity, и он возвращает объект JSON со всеми данными в нашем документе. В этой демонстрации возврат всех данных не имеет большого значения. Для более крупных реализаций GROQ допускает необязательную «проекцию» для возврата только тех явных полей, которые вам нужны.
const client = require('./utils/SanityClient') // at the top of the file // ... async function getSanityData() { const query = `{ "about": *[_id == 'YOUR-ID-HERE'][0] }` let data = await client.fetch(query); }
Преобразование поля форматированного текста в HTML
Прежде чем мы сможем вернуть данные, нам нужно выполнить преобразование в нашем расширенном текстовом поле. В то время как многие CMS используют редакторы форматированного текста, которые возвращают HTML напрямую, Sanity использует спецификацию с открытым исходным кодом под названием Portable Text. Portable Text возвращает массив объектов (представьте форматированный текст как список абзацев и других медиаблоков) со всеми данными о стилях и свойствах форматированного текста, таких как ссылки, сноски и другие аннотации. Это позволяет перемещать текст и использовать его в системах, не поддерживающих HTML, таких как голосовые помощники и собственные приложения.
В нашем случае это означает, что нам нужно преобразовать объект в HTML. Существуют модули NPM, которые можно использовать для преобразования переносимого текста в различные приложения. В нашем случае мы будем использовать пакет block-content-to-html.
npm install @sanity/block-content-to-html
Этот пакет будет отображать всю разметку по умолчанию из редактора форматированного текста. Каждый тип стиля можно переопределить, чтобы он соответствовал любой разметке, необходимой для вашего варианта использования. В этом случае мы позволим пакету сделать всю работу за нас.
const blocksToHtml = require('@sanity/block-content-to-html'); // Added to the top async function getSanityData() { const query = `{ "about": *[_type == 'about'][0] }` let data = await client.fetch(query); data.about.content = blocksToHtml({ blocks: data.about.content }) return await data }
Использование контента Sanity.io в рулях
Теперь, когда данные в форме, мы можем их использовать, мы передадим их нашей функции buildHTML
в качестве аргумента данных.
async function main(src, dist) { const data = await getSanityData(); const html = buildHTML(src, data) fs.writeFile(dist, html, function (err) { if (err) return console.log(err); console.log('index.html created'); }); }
Теперь мы можем изменить наш HTML, чтобы использовать новые данные. Мы будем использовать больше вызовов переменных в нашем шаблоне, чтобы получить большую часть наших данных.
Чтобы отобразить нашу переменную форматированного текстового content
, нам нужно добавить дополнительный слой фигурных скобок к нашей переменной. Это укажет Handlebars отображать HTML вместо отображения HTML в виде строки.
Для нашего массива externalLinks
нам нужно будет использовать встроенную функцию зацикливания Handlebars, чтобы отобразить все ссылки, которые мы добавили в нашу студию.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{ about.title }}</title> </head> <body> <h1>The personal homepage of {{ about.fullName }}</h1> {{{ about.content }}} <h2>Bryan is on the internet</h2> <ul> {{#each about.externalLinks }} <li><a href="{{ this.href }}">{{ this.text }}</a></li> {{/each}} </ul> </body> </html>
Настройка развертывания
Давайте сделаем это в прямом эфире. Для работы нам нужны два компонента. Во-первых, нам нужен статический хост, который будет создавать для нас наши файлы. Затем нам нужно инициировать новую сборку нашего сайта при изменении контента в нашей CMS.
Развертывание в Netlify
Для хостинга мы будем использовать Netlify. Netlify — это хостинг статических сайтов. Он обслуживает статические ресурсы, но имеет дополнительные функции, которые сделают работу нашего сайта бесперебойной. У них есть встроенная инфраструктура развертывания, которая может запускать наш сценарий узла, веб-перехватчики для запуска сборок и глобально распределенная CDN, обеспечивающая быстрое обслуживание нашей HTML-страницы.
Netlify может просмотреть наш репозиторий на GitHub и создать сборку на основе команды, которую мы можем добавить на их панель управления.
Во-первых, нам нужно отправить этот код на GitHub. Затем в Netlify Dashboard нам нужно подключить новый репозиторий к новому сайту в Netlify.
Как только это будет подключено, нам нужно сообщить Netlify, как построить наш проект. На панели инструментов мы перейдем в «Настройки»> «Сборка и развертывание»> «Настройки сборки». В этой области нам нужно изменить нашу «Команду сборки» на «node index.js» и наш «Каталог публикации» на «./dist».
Когда Netlify создаст наш сайт, он выполнит нашу команду, а затем проверит папку, которую мы перечисляем, на наличие содержимого и опубликует содержимое внутри.
Настройка вебхука
Нам также нужно указать Netlify публиковать новую версию, когда кто-то обновляет контент. Для этого мы настроим Webhook, чтобы уведомить Netlify о том, что нам нужно перестроить сайт. Webhook — это URL-адрес, к которому может программно обращаться другая служба (например, Sanity) для создания действия в исходной службе (в данном случае Netlify).
Мы можем настроить конкретный «хук сборки» на нашей панели управления Netlify в «Настройки»> «Сборка и развертывание»> «Сборочные крючки». Добавьте хук, дайте ему имя и сохраните. Это предоставит URL-адрес, который можно использовать для удаленного запуска сборки в Netlify.
Затем нам нужно сообщить Sanity, чтобы он делал запрос на этот URL-адрес при публикации изменений.
Для этого мы можем использовать Sanity CLI. Внутри нашего каталога /studio
мы можем запустить sanity hook create
для подключения. Команда запросит имя, набор данных и URL-адрес. Имя может быть любым, набор данных должен быть production
для нашего продукта, а URL-адрес должен быть URL-адресом, предоставленным Netlify.
Теперь всякий раз, когда мы публикуем контент в Studio, наш сайт будет автоматически обновляться. Каркас не нужен.
- Код можно найти в этом репозитории GitHub →
Следующие шаги
Это очень маленький пример того, что вы можете сделать, когда создаете свои собственные инструменты. В то время как более полнофункциональные SSG могут быть тем, что вам нужно для большинства проектов, создание собственной мини-SSG может помочь вам лучше понять, что происходит в выбранном вами генераторе.
- Этот сайт публикует только одну страницу, но с небольшим дополнением в нашем скрипте сборки мы могли бы опубликовать больше страниц. Он может даже опубликовать сообщение в блоге.
- В репозитории немного не хватает «Опыта разработчика». Мы могли бы запускать наш Node-скрипт при сохранении любых файлов, реализовав такой пакет, как Nodemon, или добавить «горячую перезагрузку» с чем-то вроде BrowserSync.
- Данные, хранящиеся в Sanity, могут использоваться для работы нескольких сайтов и служб. Вы можете создать сайт резюме, который использует это и публикует PDF вместо веб-страницы.
- Вы можете добавить CSS и сделать его похожим на настоящий сайт.