posts projects about

СтихТок

2 февраля 2024 г.

Когда пришла эпоха коротких видео в TikTok и YouTube, я, как и многие, стал проводить там слишком много времени, порой обнаруживая себя засыпающим в 5 утра под листание бесконечной ленты. Тогда я решил отучить себя от этой привычки. Пробовал разные ограничения, но, в конечном итоге, просто забивал на них.

Примерно в это же время я увлёкся поэзией. Мне было около 30, когда я научился получать удовольствие от чтения стихов. И я подумал — а почему бы не заменить короткие видео на стихи. Тогда каждый раз, когда я хотел позалипать в тикток, я вместо этого открывал случайное стихотворение какого-нибудь автора, читал несколько стишков, закрывал, и возвращался к делам.

Если подумать, то стихи — это тиктоки 20 (19, 18 …) века. Но красивое стихотворение вызывает более сильные чувства, чем любое короткое видео, и, что самое важное, к нему хочется возвращаться, перечитывать, и вновь получать удовольствие от красоты написанного. А особенно понравившиеся стихи, учить наизусть.

Так у меня появилась идея полушутя-полусерьезно сделать приложение с тикток механикой, но вместо видео — стихи.

Nocode VS Code

Я ничего не знал о фронтенд разработке и решил попробовать nocode-инструменты. 

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

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

Зачем тогда вообще этот уровень абстракции? 

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

Всё-таки code

Так я начал смотреть в сторону React Native, но нашел еще более простое решение — PWA (progressive web app). Это технология, которая позволяет сделать приложение из обычного сайта. Сейчас многие банки, приложения которых недоступны в AppStore, используют эту технологию. PWA — это когда можно на смартфон «установить» сайт. На домашнем экране появится иконка приложения, если его запустить, то откроется сайт, но без интерфейса браузера. Как будто нативное приложение.

Установка PWA-приложения

В Safari в меню Поделиться есть пункт “На экран Домой», который установит PWA на домашний экран. В Chrome на Android в контекстном меню есть пункт «Установить приложение»

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

Backend

Бэкенд я сделал на DjangoRestFramework, потому что это быстро и удобно. Мне нужен простой API, в который я буду обращаться из JS-приложения. В качестве базы данных использую PostgreSQL.

Frontend

Для фронтенда я выбрал ReactJS, т.к. это самый распространённый фреймворк. Я никогда не писал на JS, поэтому учился этому с нуля, и то, что у ReactJS большое комьюнити, мне очень помогло в изучении. Если тоже начинаете изучение React, могу посоветовать вот этот бесплатный курс.

Чтобы из сайта сделать PWA-приложение, он должен соответствовать нескольким требованиям:

  • обязательный HTTPS
  • manifest с описанием
  • наличие service worker-а.

Service worker — это js-код, который выступает посредником между приложением и интернетом, т.е. все запросы в API, которые будет отправлять приложение, будут отправляться через этот воркер.

Он может кэшировать их, обрабатывать ситуации плохой связи или её отсутствия, чтобы пользователь не увидел ошибку браузера, а увидел вашу собственную “заглушку”, что нет связи. Вообще, тема service worker-ов очень обширна, на Хабре можно найти подробные статьи об этом. Я же сгенерировал свой воркер в сервисе pwabuilder.com

PWA-приложение без интернета

Здесь я отключил интернет, и вместо браузерного ERR_NETWORK_ERROR, вижу собственное красивое сообщение об ошибке. За это отвечает service worker.

После добавления воркера, выяснилось, что самая популярная JS-библиотека для HTTP-запросов axios, не умеет работать через него. Пришлось заменить axios на ky.

axios не работает с сервис воркером

Ky работает через Fetch, поэтому подходит для использования с service worker.

Проблема превью в мессенджерах

Мое приложение — это SPA на ReactJS, поэтому по GET запросу любой страницы веб-сервер возвращает пустой HTML, а дальше отображением занимается JS-код внутри браузера, изменяя DOM-дерево «на лету». И если, например, делиться ссылкой в Телеграме на какую-либо страницу сайта, то на превью будет якобы пустая страница, хотя внутри браузера у пользователя есть контент, но превью-генераторы не умеют рендерить JS, они просто посылают GET запрос, и на основе полученного пустого HTML рисуют превьюшку в чате. Та же ситуация и с поисковыми ботами Google и Яндекс.

Для решения этой проблемы, я нашел вот такой контейнер — https://github.com/tvanro/prerender-alpine . Внутри headless chrome, который любезно срендерит JS за поискового бота или генератора превьюшек в мессенджерах. На входящем nginx-е я строю маршрутизацию запроса на основе заголовка User-Agent, и, если это поисковой бот или превью-генетатор, то проксирую этот запрос в пререндер-контейнер, который вернет HTML-страницу с отрисованным контентом.

Вот только я еще не решил — это изящное решение архитектурной проблемы, или ужасный костыль?

Перед публикацией статьи, увидел, что у поискового бота Яндекса появилась бета-версия “Рендеринга страниц JavaScript”

Deploy

Когда пришла пора деплоить приложение в прод, я купил домен stihtok.ru, и подыскал VPS-хостинг. Мне понравился TimeWeb Сloud, я взял самую дешевую виртуалку и сделал ansible-плейбуки для установки необходимого окружения на сервере.

Разумеется, все работает в докере. Для автоматизации сборки контейнеров я использую GitHub Actions с собственным раннером на сервере. По коммиту в ветку происходит сборка и деплой на тестовый стенд, а отведение тэга деплоит его на прод.

Вот такое получилось приложение: https://stihtok.ru

СтихТок

Весь код открыт на Github - https://github.com/stihtok

Happy end

Больше я не залипаю до утра в ТикТоке… я делаю это в СтихТоке :)