Переписал сайт на SvelteKit

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

Причины переезда

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

Желание всё упростить

Для простенького блога предыдущий стек был чрезмерно требовательным в плане ресурсов на поддержку. Обновление зависимостей занимало много времени, производительность дев-сервера была невысокой, React и TypeScript требовали разных «церемоний», прежде чем я мог добавить новую страницу или фичу. Хотелось быстрее, дешевле и проще.

Next не подходит для SSG

В Next мне нравился старый постраничный роутинг и встроенный во фреймворк SSG, но меня никак не оставляло ощущение, что его делали «по остаточному принципу». Многие вещи приходилось велосипедить самостоятельно, что отъедало время, а страницы, которые получались в результате генерации, казались неоправданно тяжёлыми. Хотелось инструмент поудобнее.

Новый стек

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

Astro показался интересным, но со SvelteKit я был уже немного знаком — я написал на нём веб-версию книжки о рефакторинге в прошлом году — потому выбрал его.

От TypeScript я решил в этот раз уйти. Большая часть кода в блоге — инфраструктура, которую я вряд ли буду часто менять, поэтому большой пользы от TypeScript я бы не получил, а нагрузка на поддержку снова бы выросла.

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

Чейнджлог

Изменений оказалось много. Кроме изменений «инфраструктуры» я заодно обновил дизайн, обновил структуру контента в репозитории и перевёл некоторые старые посты на английский.

Передизайнил страницы

Давно хотел и вот наконец освежил дизайн главной и других страниц. Редизайн списка статей вдохновлён сайтом Андрея Романова, а редизайн страницы проектов — сайтом Салавата Абдуллина. Если читаете — спасибо вам!

Кроме этого я избавился от отдельных страниц для каждого из проектов. Теперь ссылки ведут напрямую в сами приложения, книги или проект на Гитхабе. Все кулстори о процессе работы над проектами и их релизах (например, «Как мы запускали MRKT») я переместил в блог.

Заодно немножко подправил семантику и структуру заголовков на текстовых страницах.

Переосмыслил теги

Теги стали чуть более полезными. Каждый тег теперь — это «тематическая подборка» всего, что я написал, накодил и наговорил по теме. Такие подборки удобно, например, скидывать в ответ на запросы «Что почитать о X?», которые я иногда получаю в почте или ишьях на Гитхабе.

Также я использую теги для поиска и перелинковки схожего контента — то, что я давно хотел сделать, но всё руки не доходили. Пока что я добавил раздел «Связанные темы» только на страницу тега, но я планирую добавить похожий раздел и на страницу отдельной статьи.

Воскресил старые посты

Опубликовал некоторые посты, которые потерялись при самом первом переезде сайта с MODX на JAM-стек. Какие-то из них лежали в черновиках, какие-то был распубликованы (уже не помню, почему). Среди таких постов, например:

В общем, раскопал, воскресил, перевёл на английский, опубликовал.

Улучшил структуру контента в репозитории

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

Новая структура контента помогает читать статьи прямо на Гитхабе — выглядит довольно сносно:

Как статья об игре «Жизнь» рендерится на Гитхабе. Особенно доволен, как смог не потерять ссылки на YouTube, которые заменяют собой кастомный компонент с iframe
Как статья об игре «Жизнь» рендерится на Гитхабе. Особенно доволен, как смог не потерять ссылки на YouTube, которые заменяют собой кастомный компонент с iframe

Гитхаб правда не рендерит alt-текст изображений как подпись к figure, из-за чего иногда картинки показываются без дополнительного контекста, но я посчитал, что это не очень критично.

Почистил изображения

Удалил из постов картинки в устаревших™ растровых форматах (jpg, png) и оставил только webp, поддержка которого уже около 96%.

Заодно удалил всё, что было связано с автоматизированной минификацией и ресайзом изображений. Пишу посты я не очень часто, изображений там не очень много, поэтому наворачивать инфраструктуру для автоминификации, ресайза и конвертации в разные форматы мне показалось дорого и бесполезно. Решил просто готовить изображения руками.

Результаты

Из примечательного могу выделить качество генерируемых страниц и скорость работы стека.

Легковесные страницы

Я использую Static Adapter для генерации страниц, и мне нравится, что у него есть опция «не использовать CSR». Страницы на выходе получаются простые, лёгкие, а главное — никакого клиентского JS там, где он не нужен.

Быстрый старт и дев-сервер

Vite, который работает под капотом у SvelteKit, действительно стартует и собирает сайт значительно быстрее, чем мой предыдущий стек с Next. Даже на моём стареньком домашнем ноутбуке проект стартует почти мгновенно.

Быстрая сборка и деплой

Билдер быстрый, поэтому сборка занимает не больше полуминуты, а небольшой вес страниц делает быстрым деплой.

Упрощённая структура

В этот раз я решил особо не упарываться по «чистоте кода». Причины здесь примерно те же, что и для отказа от TypeScript: я вряд ли буду часто менять этот код.

Отсутствие ограничений уменьшает трение перед стартом новой фичи, страницы, или проверки какой-то идеи. Так как я работаю над проектом один, «энфорсить лучшие практики на команду» смысла особого нет, зато количество времени на разработку уменьшается ощутимо.

Инфраструктурные хаки

Не всё, однако, идеально гладко. Пришлось, например, немного повозиться с интеграцией «кастомных компонентов» типа YouTube и Switch в статьях. Не нашёл какого-то удобного инструмента, поэтому накостылил автоимпорт. Надеюсь, не придётся его часто трогать из-за мажорных изменений в SvelteKit.

Впечатления

В целом, новым стеком я доволен. Нравится, что роутинг постраничный, что серверный код не смешивается с клиентским и что используются стандартные штуки из платформы.

Отдельно понравились «серверные страницы», и как они ренденрятся при статической генерации. В прошлом стеке приходилось костылить, чтобы сгенерировать RSS-ленту, SvelteKit же даёт возможность написать +server.js файл и указать, как его отрендерить при сборке — чтобы на выходе получился rss.xml.

Сам Svelte тоже нравится больше, чем React. Как минимум не нужно придумывать 100500-й способ прикручивать стили — всё уже продумано за меня. Есть, конечно, ограничение, что в Svelte компонент — это один всегда файл, но зато внутри него лежит всё что ему нужно: разметка, стили, логика.

Есть небольшое ощущение, что для генерации статических блогов SvelteKit сыроват, потому что есть проблемы с рендерингом Markdown-файлов и компонентов внутри него 1, 2, 3, 4, но возможно, это исключительно моя проблема из-за динамических компонентов внутри статей.

В любом случае, все эти проблемы фиксятся костылями, а количество костылей в этот раз получилось сильно меньше, чем в прошлый.

Ссылки и ресурсы

Всякие там технологии

Редизайн вдохновлён