Jekyll → Gatsby
На днях сайт обновил движок. Последний раз это случалось в 2013-м — тогда сайт переехал с Wordpress на Jekyll, сейчас — с Jekyll на Gatsby.
Мои вопросы про Gatsby вызвали довольно оживленную дискуссию в твиттере (1, 2), поэтому я решила отдельно рассказать про смену движка и опыт с Gatsby.
Поначалу Jekyll был довольно удобным, но со временем стал тесноват. Во-первых, сборка страниц и стилей мееедлееенная, во-вторых, он на Ruby, и если какие-то пакеты устаревали и сайт превращался в тыкву, приходилось срочно вспоминать/гуглить команды для обновления Ruby-пакетов. Когда сборка сайта запускается нечасто, и он на непривычной экосистеме, обновление может занять значительное время, а это не совсем то, чем хотелось бы заниматься, если изначально зашел просто поправить пару абзацев.
Со старыми проектами такое случается: иногда нужно обновить кучу пакетов, прежде чем он в принципе запустится. Устаревающие внешние зависимости могут усложнить жизнь независимо от экосистемы, к которой они принадлежат. Они могут оказаться несовместимы со свежей версией ноды, обновленной операционной системой или просто пакет перестаёт поддерживаться и вы больше не можете его установить — и проект двух-трёхлетней давности уже не запустить (было и такое). Будете ли вы тратить время на попытки его оживить, перепишете полностью или похороните навсегда? Внешние пакеты, которые делают что-то за вас, облегчают разработку, но делают финальный результат хрупким.
Так что идея иметь как можно меньше зависимостей — хорошая и правильная, но выбирая новый движок я, честно говоря, не особо озадачивалась этим вопросом. Персональный сайт, на мой взгляд, — это не только блог, но и песочница, где можно поиграться с чем-то новым, выбирая движок не столько по практическим характеристикам, сколько по интересующим технологиям, поэтому в этот раз в качестве движка был выбран Gatsby: меня интересовали GraphQL и React, которые нём используются.
Мне удалось сделать желаемый сайт, и сам процесс разработки был достаточно комфортным, но Gatsby, скорее всего, не самый лучший выбор для генерации простого статического сайта, и если вы планируете сделать подобное, попробуйте рассмотреть другие варианты. Можно воспользоваться Eleventy, который рекомендует Вадим Макеев или подобрать другой движок на сайте StaticGen.
Из плюсов Gatsby — мне понравилось с помощью GraphQL запрашивать данные из постов. В визуальном интерфейсе можно накликать нужное, а потом выполнить запрос и проверить что он вернул:
Минусов у Gatsby довольно много.
Первое, с чем я столкнулась — в пост невозможно вставить демки с Codepen. Обычный код для встраивания просто не работает, я так понимаю, это общая проблема проектов на React. В статьях используется более двухсот демок с кодепена, так что это стало серьёзной проблемой. Для её решения мне пришлось написать небольшой плагин, который во всех статьях при генерации страницы меняет обычный код для встраивания на код с iframe
.
Следующая проблема: при локальной разработке не отображаются фреймы, лежащие в папке со статикой, и таких демок на сайте тоже довольно много. Чтобы это заработало, в папке public/
нужно запускать отдельный сервер.
В принципе, уже на этом моменте можно было остановиться и подумать, а действительно ли мне нужен именно Gatsby или лучше пойти поискать другой генератор статики. Движок не должен за меня решать что и как я буду вставлять в свои посты. Ёжики плакали, кололись, но я решила довести дело до конца и доделать сайт на выбранном движке.
Следом передо мной встал вопрос лишнего веса: дефолтная сборка делает для всех страниц статическую версию, но сайт ведёт себя как одностраничное приложение: переходы между страницами происходят с помощью замены контента без перегрузки страниц. Чтобы это происходило максимально быстро, приложение в фоне подгружает контент страниц, куда теоретически может перейти пользователь. Если просто открыть главную страницу, загрузится основной контент страницы и содержимое ссылок, попавших в первый экран.
Вес разметки — около 60kB, + какой-то минимальный JS весом до 10kB, из картинок только мелкие иконки, но в итоге страница весит полмегабайта, всё остальное добавил Gatsby.
Мотаем вниз, приложение обнаруживает новые ссылки и подгружает их тоже. Теперь страница весит 1.7 мегабайт, и ещё 3 мегабайта загружено по сети:
А я просто промотала страницу вниз.
Цель этих подгрузок — максимально быстро показать следующую страницу, но если точно известно, что на страницах нет ничего тяжёлого, может, и не нужно как-то специально ускорять переход между ними?
Я воспользовалась плагином gatsby-plugin-no-javascript, который удаляет из разметки все скрипты, которые добавляет туда движок, и это значительно уменьшило количество запросов и вес загружаемых ресурсов:
Предзагрузка соседних страниц, на мой взгляд, хорошая идея для интернет-магазина или новостного сайта, где попав на одну страницу, посетитель с высокой степенью вероятности пойдёт гулять по соседним, но для небольшого редко обновляемого сайта это не очень нужно.
На мой сайт часто заходят посетители из поиска за каким-то конкретным вопросом, и здесь нет необходимости подгружать фоном соседние страницы, потому что они могут никогда не понадобиться. Кроме того, страницы со статьями сами по себе весят немного и ускорять их загрузку подгружая контент заранее, по-моему, просто незачем.
Статьи с картинками, демками и счётчиками, конечно, будут весить больше чем главная, на которой только текст, но в любом случае теперь к их весу не будет добавляться вес скриптов, которые загружаются на всякий случай и, чаще всего, будут просто не нужны, потому что пользователь нашёл нужное и закрыл страницу.
Если бы мне не удалось снизить вес страниц до приемлемого, возможно, мне пришлось бы всё-таки переписать сайт ещё раз.
Про gatsby-plugin-no-javascript ещё нужно помнить следующее: он хорошо убирает лишнее, но вместе с лишним удаляются и все события и хуки из реакт-компонентов. При использовании плагина всю интерактивность нужно вынести во внешние скрипты, так что тут придется выбирать: или реакт, или лёгкий сайт — одновременно не получится.
Осталась ещё пара небольших проблем. Первая: для управления содержимым тега head
предлагается использовать react-helmet, а он оставляет в коде много лишнего: у каждого тега в шапке будет атрибут data-react-helmet="true"
. Я так понимаю, при использовании с реактом он нужен, чтобы метатеги не двоились, но в статической версии сайта атрибут совершенно ни к чему.
Решить эту задачу помогла подсказка от Владимира Кузнецова. В Gatsby Node APIs есть метод onPostBuild
, который позволяет изменять HTML-файлы после сборки. С его помощью я удалила из кода data-react-helmet="true"
и некоторые другие хвосты, которые туда добавил Gatsby.
Вторая проблема — куча лишних файлов, которые по-прежнему попадают в сборку, хотя уже нигде не используются: для них я добавила скрипт в package.json
, он запускается при деплое и удаляет ненужное.
Upd от 31.07.2020: удаление файлов может вызывать проблемы при последующем локальном запуске проекта, поэтому было найдено другое решение. В static/
кладется файл .gitignore
и в него добавляются все пути, которые нужно игнорировать. После этого в команду для плагина gh-pages
нужно добавить параметр --dotfiles true
, чтобы .gitignore
не игнорировался при отправке содержимого в ветку.
Вот так с помощью напильника и такой-то матери мне удалось довести сайт до желаемого состояния и приемлемого веса. Gatsby может использоваться для генерации простых статических сайтов, но придется приложить некоторые усилия, чтобы сайт на выходе действительно был лёгким и простым, дефолтная сборка этого не делает.
Возиться с Gatsby было забавно, но когда я в следующий раз захочу переписать сайт, скорее всего, выберу что-то другое.
- Ссылки по теме:
- Gatsby
- Jekyll
- GraphQL
- React
- Eleventy
- StaticGen
- Your blog doesn’t need a JavaScript framework
- Метки:
- инструменты