Давно я ничего не писал, и вообще меня мало было слышно. Но это не потому что я "завязал", а просто потому что новое хобби оказалось очень объемным и сложным, потребовавшим много времени на изучение и на то, чтобы в итоге можно было действительно что-то вменяемое показать. Хобби - это все то же самое - node.js и т.п. Да, в прошлой статье я писал, что применил эти технологии здесь, но все равно здесь это совсем еще не то. Здесь это еще совсем начальные эксперименты были, а вот на другом своем проекте я боле менее серьезные вещи уже реализовал. Другой проект - это Городские-бани.ру, про которые я ранее уже писал, и которые сейчас пережили очередную реинкарнацию. Бани тоже еще не совсем законченные, там много чего еще сверху навернуть надо, но в целом основа заложена очень интересная, уже есть чем поделиться. К сожалению, я в этой статье не приведу подробные рецепты работы и готовые решения, но если кто любит почитать что-нибудь просто для расширения кругозора, вполне статья может оказаться интересной. Для начала кратко опишу стек технологий:
- Изначально бэкэнд полностью на MODX был, сейчас MODX - это хранение основной части информации + политики безопасности.
- Фронт - react+material-ui+graphql+google-map-react+draft-js и т.п., в общем сплошь JavaScript.
- Между всем этим node-js+react-dom-server, обеспечивающий запросы на MODX и серверный рендеринг.
Уверен, для многих это все покажется очень сложно и громоздко, но уверяю, все не так на самом деле. На самом деле все еще гораздо сложнее))). Можно сказать, что я слишком увлекся несколькими отдельными, занятными на первый взгляд, но не всегда совместимыми друг с другом, технологиями, и с учетом того, что это проект мой и за все эксперименты я несу ответственность только перед собой, я позволил себе гораздо больше, чем, может, имел права. В итоге я несколько раз переписывал проект в различных вариациях, и на сегодня получил боле менее взвешенный результат, который и поисковиков не сильно расстраивает, и мобильные устройства пользователей не делает плакать, да и вообще вроде нормально работает.
Перейду от сложного сухого текста к описанию проекта со скриншотикам, чтобы было понятней о чем вообще речь...
Вообще изначально я хотел сделать картографический сервис, где главной страницей была бы карта. Сейчас карта несколько на второй план ушла, но все равно является большой частью проекта. Вот прямая ссылка на карту, если вдруг кто не заметит сразу кнопку: https://gorodskie-bani.ru/moscow/@55.7485,37.6184,12 Почему карта ушла на второй план? Вот тут я, что называется, получил удар оттуда, откуда не ожидал... Засада оказалась в том, что на сегодня доля мобильного трафика сайта составляет почти 70%. У меня не топовый телефон, но и не самый слабый, и даже с него, заходя на сайт с картой, объективно, я мог начать взаимодействовать с сайтом только секунд через 20-30. Все потому что почти мегабайт javascript + загрузка гугло-карты с прочими сторонними ресурсами - это довольно много для того, чтобы телефон мог это все быстро пережевать. С компьютерами такой проблемы нет, но если бы доля мобильного была не более 10%, то я мог бы еще закрыть глаза на это, а так не могу. В итоге пришлось переосмысливать проект и переписывать его. А переписать пришлось очень многое... Дело в том, что изначальная реализация проекта была довольно оригинальная: связка react+graphql+flux+immutable позволила мне организовать такую систему, что на сторону браузера загружались все сырые данные разом, после чего сайт работал как полностью автономное веб-приложение, которому интернет уже почти не был нужен (только для подгрузки картинок). По нему можно было часами лазить без единого запроса на сервер, и работало это очень быстро. И вот от этого пришлось отказаться, но плюс к этому переписать и организовать подгрузку нужных данных так, чтобы это не ударило по функционалу, и не было много лишних запросов на сервер. И в итоге переписал.
Итак, какие же фишки на выходе получились, что я так много буков написал уже?
1. Довольно интересная подача контента в зависимости от того, куда пользователь зашел при первом посещении. Алгоритм такой:
- Сначала из адресной строки берутся гео-данные, если они указаны, то есть как в ссылке выше @55.7485,37.6184,12. Если пользователь заходит на страницу с такой меткой, то не важно откуда он, "гео-центр" сайта фиксируется в этом положении и все карточки заведений выстраиваются относительно этого центра, то есть в первую очередь будут выводиться ближайшие, и в последнюю очередь наиболее отдаленные.
- Если гео-меток нет в адресной строке, то берутся данные из самой страницы. Это может быть страница города (если пользователь зашел на страницу с указанием города), и тогда центр берется от этого города, или данные организации, если он попал на нее. Таким образом даже в рамках одного города, в зависимости от того, в какую часть сайта пользователь попал. ему будет выдан тот или иной контент. Это сделано из соображений того, что как правило при поиске бань пользователю очень критичен географический аспект, и если те бани, что он искал, в данный момент закрыты или типа того, если если и заинтересуют другие заведения, то скорее всего только поблизости. Все остальное для него не будет иметь значения.
- Если гео-данные не удалось определить на основании контента, то тогда уже берутся данные самого пользователя на основе geoip.
В дальнейшем планируется еще расширить логику определения геоданных содержимого. В частности, уже сейчас можно, к примеру, из статей-обзоров заведений, привязанных к заведениям, и их комментариев, определять гео-принадлежность контента. На мой взгляд, такой подход очень положительно может сказаться на гео-подаче сайта в рамках страны и за ее пределами, так как поисковики довольно хорошо в наше время определяют откуда пользователь и какой контент в индексе соответствует его региону. И когда пользователь попадает на страницу с географической принадлежностью, перейдя с этой страницы на главную страницу сайта, он получит контент, более "близкий" к нему, а не все подряд от корня с предложением "Пожалуйста, укажите свой город". Даже города в главном меню выстраиваются в порядке удаленности от текущего определенного города, и если вы начнете двигать карту в сторону других городов, увидите, что список городов в главном меню меняется.
Если кому не лень, зайдите на главную страницу https://gorodskie-bani.ru/ и потом отпишитесь в комментариях, все ли так, определилось ли ваше местоположение и были ли в первую очередь показаны заведения, наиболее близкие к вашему местоположению? 2. В этом же ключе в самих карточках заведений есть дополнительный блок "Другие заведения поблизости". Так же берутся ближайшие к текущему заведения.
3. Довольно оригинально реализован редактор графика работ. В банях есть, кроме общего графика, мужские дни, женские, семейные. Вот так это работает:
4. Отдельная история - редактировние объектов на сайта. После долгих размышлений, я пришел к выводу, что любой должен иметь возможность редактировать информацию в заведениях, даже не будучи авторизованным. Почему я так решил? Да ведь полно примеров в том же 2gis и яндекс-справочниках, когда люди в комментариях пишут типа "А здесь цены уже не такие, а такие", или "График поменялся, теперь он такой". При чем эти комментарии не редко пяти-шестилетней давности, и их много и они противоречат друг другу. И не ясно что сейчас актуально. Я считаю, что если человек знает что-то и хочет поделиться этим, то ничто не должно ему мешать это сделать, и даже не надо требовать авторизацию. На банях это именно так и реализовано. И тут, конечно же, каждый спросит "а как же безопасность и т.п.?". Отвечу: с этим все ОК. Алгоритм следующий:
- Если права у пользователя есть на редактирование объекта, то пусть сохраняет (это может быть как администратор, так и владелец заведения).
- Если это авторизованный пользователь, но у него нет прав на этот объект, или это анонимный пользователь, то им сообщается в духе "Ваша заявка принята, после проверки модератором данные появятся на сайте" и измененные данные сохраняются в таблицу версий. Есть даже отдельная страница для вывода статистики изменений https://gorodskie-bani.ru/edits Я, будучи суперпользователем, вижу в том числе и какие данные были переданы. Данные в техническом виде, но мне их достаточно.
Вот как происходит модерация и принятие изменений:
5. Оригинальный редактор текста. Это такой же редактор как и здесь, то есть на базе draft-js, но значительно доработанный. В частности, можно вставлять как отдельные картинки, так и целые галереи. Но главное - это можно вставлять ссылки на другие заведения, и выводиться потом будет не просто ссылка, а карточка заведения, выводимая по клику.
Этот же редактор и в комментариях можно использовать, то есть тоже ссылки на объекты вставлять. В дальнейшем можно будет в карточке компании выводить все упоминания в статьях и комментариях.
Но главная фишка - это, конечно же, серверный рендеринг. При чем не просто так, а практически зеркальный тому, что происходит на клиенте. И здесь не все так однозначно. Довольно много статей написано, касательно SSR, но далеко не во всех статьях уделяется внимание тому моменту, что работа реакта на клиенте и на сервере, по большому счету, сильно отличается. По больше степени это касается того, что на клиенте реакт работает циклически, обрабатывая все изменения состояния и входящих параметров. Пример: Для полного рендеринга данных в компоненте, вам надо запросить данные с удаленного сервера Ajax-запросом, получить их, закинуть в стейт компонента, после чего он выполнит ре-рендеринг с этими данными. Ajax-запрос выполняется асинхронно, а в реакте нельзя заблокировать работу компонента, так, чтобы он отрендерился только после получения данных. В реакте можно только отработать компонент, потом заставить его повторно отрендериться, при чем делать это сколько угодно раз. А вот на сервере с реакт-компонентом этого сделать нельзя. Там повторного рендеринга нет, все необходимые данные должны быть переданы еще на входе. Честно сказать, это задача, которую я до конца не решил. Дело в том, что на фронте, по мере получения данных и ререндеринга компонентов, могут в вывод приходить новые компоненты, которые тоже будут запрашивать еще другие компоненты и т.д. То есть всей цепочки предугадать очень сложно. В итоге пришлось сайт разбить на какие-то отдельные, боле менее понятные блоки, в которых легче прогнозировать весь необходимый для рендеринга набор данных и работать с ними.
Послесловие: поработав уже довольно продолжительное время со всеми этими технологиями, хочу отметить, что технический уровень современных проектов по-прежнему растет. Я давно работаю с MODX (и не только с ним работал), и есть с чем сравнивать. Могу точно сказать, что на чистом MODX такое было бы мне очень сложно сделать. И тут следует оговориться: дело не столько в самом MODX. Дело в том, что в случае с MODX (реализации проекта на нем и используя его для шаблонизации), мы делаем параллельно как бы два проекта: один на сервере, для всей серверной логики, а второй на фронте (javascript и т.п.). В этом случае клиентская логика и серверная как бы отделены друг от друга. Они как бы живут каждый своей жизнью. Ввести в таких условиях какую-то хитрую динамику на стороне браузера - сложное занятие, потому делается это в рамках, как правило, только необходимого. В случае же с react, граница между клиентом и сервером размывается. И это очень интересно.