Карта Кипра с "рабочими местами" для цифровых кочевников
Карта Кипра с "рабочими местами" для цифровых кочевников

Продолжение рассказа про разработку pet-проекта о кафе и коворкингах на солнечном Кипре. «Рабочие места» для цифровых кочевников ヽ(。_°)ノ

В первой части я рассказал про REST API микросервис, теперь - про фронтэнд-сайт.

Всё удалось, код проекта открыт, велкам в пул-реквесты. Адрес сайта - в конце статьи, чтобы меньше походило на рекламу.

Архитектура

Сайт реализован в виде PWA на Vue 3 Composition API и UI-фреймворке Vuetify. Оба инструмента хорошо подходят для быстрого старта проекта с нуля и содержат меньше избыточного кода, нежели предыдущие версии.

Основная часть сайта - это карта Google Maps в always free tier, на которую выводятся данные из REST API микросервиса, а также панель с фильтрами и списком "рабочих мест".

"Входной" компонент src/components/Home.vue:

  • управляет отображением разделов для мобильной и десктопной версии;

  • управляет данными из API, которые получает из src/composable/api.js;

  • обрабатывает их computed фильтрами из src/components/Filters.vue;

  • передаёт отфильтрованные данные в компонент src/components/Places.vue для отображения списка мест;

  • обрабатывает ошибку 404;

  • устанавливает мета-теги через компонент src/components/PlaceHead.vue.

Отдельной карточки "рабочего места" в проекте нет, пока достаточно простой прокрутки списка мест к нужному месту:

watch(
    () => props.selectedPlaceId,
    id => {
      scrollToPlace(id)
    }
)

Фильтры "зашиты" в код компонента src/components/Filters.vue и дополнительно стилизованы для более компактного вида.

Для работы с мета-тегами используется пакет vueuse/head.

Для отображения карты используется библиотека fawmi/vue-google-maps версии 0.9.72. В последующих версиях автор поломал карту и не выложил исходный код на GitHub (однако эти версии доступны через npm).

Также на карте можно отобразить своё местоположение и увидеть ближайшие интересные места.

Большие и маленькие фотографии мест выводятся каруселью через swiper/vue и пару своих компонентов.

Градиентный цветной рейтинг мест рассчитывается простым методом в src/composable/colors.js в цветовом пространстве hsl. В зависимости от значения рейтинга, изменяется только hue, a saturation и lightness - константы.

Для исправления возможных неточностей на карточках мест предусмотрена кнопка Complain - всё по-серьёзному :-)

Простой роутер src/router/index.js на основе vue-router позволяет пока не использовать store (при текущей функциональности проекта) и помогает в обработке 404 ошибок.

Большинство компонентов подключаются асинхронно динамически для ускорения отображения страниц, например, const Navigation = defineAsyncComponent(() => import("./Navigation.vue"))

Часть шаблона завёрнута в <KeepAlive> для кеширования компонентов при открытии/закрытии панели. Однако подружить их с Suspense для отображения заглушек не удалось :-(

Вместо дефолтных шрифтовых иконок в Vuetify, в проекте используются индивидуально импортируемые svg-иконки из пакета mdi/js от https://materialdesignicons.com. Экономия около 1 Мб в финальном бандле.

Для сборки проекта используется Vite и немного магии в vite.config.js для оптимизации итогового кода: минификации CSS и HTML, создания облегчённой версии Sentry.

PWA собирается посредством vite-pwa/vite-plugin-pwa, а его параметры также задаются в vite.config.js. В целом, реализация PWA не была самоцелью проекта, но с её помощью удалось реализовать хорошее кеширование всех частей проекта и повторное открытие сайта получилось очень быстрым.

Про Vuetify

В целом, Vuetify понравился больше, чем Quazar https://quasar.dev/ и другие UI-фреймворки. Но у него есть свои недостатки:

  • Сложность тонкой визуальной кастомизации компонентов. Vuetify рассчитан на Material Design и, например, просто так убрать отступы между чекбоксами или сделать мобильные кнопки меньше размером, не получится. В некоторых случаях придётся использовать :deep или заворачивать компоненты в дополнительные div'ы, что приводит к снижению оценки Google PageSpeed из-за большой глубины DOM.

  • Невозможность удалить неиспользуемые стили. Сборку можно очень хорошо облегчить, индивидуально импортируя компоненты и настраивая стили в SASS, но некоторую часть общих неиспользуемых стилей не получится удалить через PurgeCSS и аналогов из-за динамических названий классов.

  • Мало возможностей в некоторых компонентах, например, в слайдере.

Но, повторюсь, этот фреймворк достаточно хорош для многих проектов.

Деплой

Та же платформа Fly.io с управляемыми microVM Firecracker. Тут всё гораздо проще, чем при размещении API микросервиса и достаточно Dockerfile'а из нескольких строк и настройки заголовков в config/headerConfig.json:

FROM pierrezemb/gostatic
COPY docker/config/headerConfig.json /config/
COPY dist/ /srv/http/
ENTRYPOINT ["/goStatic", "-fallback", "/index.html"]

CI/CD

Тут чуть сложнее: сначала Github Action собирает билд при помощи Vite, а затем flyctl делает из него контейнер и деплоит на продакшн vm. Все секреты хранятся в GitHub production environment.

Мониторинг

Тот же Sentry и Honeybadger.

На этом этапе сайт работает, размещён в продакшн-окружении и доступен всем пользователям. Проект выполнен :)

Репозиторий фронтэнда, сайт https://workplaces.cy/

Комментарии (0)