Знакомимся с фронтендом

Как вы уже поняли по предыдущим заметкам, бэкенд и фронтенд Vesp не зависят друг от друга вообще никак. На прошлом занятии мы отправляли запросы в API из консоли через cURL и всё нормально работало.

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

VueJS - это реактивный фреймворк, написанный на JavaScript. В отличие от jQuery и подобных библиотек, которые манипулируют уже готовым DOM страницы: выбирают элементы, добавляют, меняют и т.д., Vue полностью строит этот DOM исходя из своих данных. То есть, для jQuery источником данных являются теги на странице, а для Vue же источником данных является сам Vue, а страница отображает его состояние.

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

NuxtJS, в свою очередь, берёт Vue и добавляет в него структуру и всякие удобные штуки, вроде серверного рендеринга. Примерно как Laravel является фреймфорком для PHP, Nuxt является фреймворком для Vue.

Вместе они позволяют писать настоящие приложения очень быстро и удобно, особенно когда в них разберёшься =)

Лично я немного пробовал и другие рективные фреймфорки: AngularJS и ReactJS, но как-то не пошло, показалось что они переусложнены. А вот Vue наоборот, очень понятный и простой. Если вы с ним еще не знакомы, посмотрите вот эту страничку.

Vesp устанавливает по умолчанию сразу 2 независимых веб-приложения: admin и site. Соответственно, админку проекта и его публичную часть. Админка генерируется в статичные файлы (html, js, css), а публичный сайт расчитан на серверный рендеринг. Их можно и нужно разрабатывать и выгружать на хостинг раздельно, они совершенно никак не связаны, только работой с одним общим бэкендом.

Файлы и директории frontend

Оба приложения находятся в соответствующих директориях в frontend/src/, а в корне frontend лежат служебные файлы:

  • .eslintrc.js - конфигурация правил линтера, про него ниже
  • .eslintignore - список файлов, исключенных из проверки линтером
  • .prettierrc - правила форматирования кода, расскажу вместе с линтером
  • ecosystem.config.js - конфигурация для запуска сервера pm2, это когда мы будем рендерить фронт на сервере
  • package.json - набор зависимостей проекта
  • webpack.config.js - ненастоящий конфиг webpack, нужен только для автодополнения в PhpStorm.

Там же директории:

  • .nuxt - кэш сборки приложений, создаётся автоматически после удаления
  • dist - а сюда собираются готовые статические приложения, так же в директории admin и site.
  • node_modules - установленные зависимости проекта
  • src - исходный код наших приложений, с которым мы и будем работать

Основной зависимостью наших фронтенд приложений является @vesp/frontend, в который я собрал всё нужное для работы - смотрите его зависимости в package.json.

Основная конфигурация проекта и всех его расширений хранится в одном-единственном файле nuxt.config.js.

Наши приложения site и admin будут наследовать и расширять именно эту конфигурацию по-умолчанию.

ESLint и Prettier

@vesp/frontend по умолчанию подключает линтер и prettier (украшатель, наверное, по-русски). Зачем они нужны?

ESLint проверяет синтаксис в исходных файлах приложения и заставляет вас исправлять ошибки во время разработки.

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

А Prettier расширяет линтер, добавляя проверку не самого кода, а его форматирования. Он регламентирует ширину отступов, правила выставления пустых строк, запятых и всего такого.

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

Например, если в правилах прописаны 4 пробела для отступов, а кто-то пихает таб, то проект просто не будет собираться и работать.

Приложение Site

Это приложение очень простое, с самым минимумом зависимостей. Конфигурация находится в frontend/src/site/nuxt.config.js и расширяет конфиг из @vesp/frontend.

Давайте посмотрим на неё:

// Импортируем нужные функции из родительской библиотеки
import {Config, findEnv, loadEnv} from '@vesp/frontend'

// Эти настройки обычно не требуется менять
// приложение поддерживает серверный рендеринг
Config.ssr = true
// директория с исходниками - это текущая директория, та где лежит конфиг
Config.srcDir = __dirname
// Цель сборки может быть static или server, то есть статичные файлы или для сервера
Config.target = 'server'
// Временная директория для файлов сборки
Config.buildDir = '.nuxt/site'
// Настройки статической генерации
Config.generate = {
  dir: 'dist/site',
  exclude: [/^\//],
}

// Здесь мы читаем наш .env файл, чтобы бэкенд и фронт использовали 
// одни и те же настройки
const env = loadEnv(findEnv('../'))
// Дальше идут настройки HTML тега head:
Config.head.title = env.APP_NAME || 'Vesp Framework'
// Здесь ссылки на иконки приложения
Config.head.link = [
  {rel: 'icon', type: 'image/x-icon', href: '/favicons/favicon.ico'},
  {rel: 'icon', type: 'image/png', sizes: '32x32', href: '/favicons/favicon-32x32.png'},
  {rel: 'icon', type: 'image/png', sizes: '16x16', href: '/favicons/favicon-16x16.png'},
  {rel: 'apple-touch-icon', sizes: '180x180', href: '/favicons/apple-touch-icon.png'},
  {rel: 'manifest', href: '/favicons/site.webmanifest'},
]

// Дополнительные расширения Nuxt
// Именно здесь подключается ESLint, например
Config.buildModules = ['@nuxtjs/style-resources', '@nuxtjs/eslint-module']
// А здесь библиотека Bootstrap-Vue с UX компонентами и PWA модуль
Config.modules = ['bootstrap-vue/nuxt', '@nuxtjs/pwa']

// Иконка Progressive Web Application
Config.pwa = {
  icon: {
    fileName: 'favicons/android-chrome-512x512.png',
  },
}

// Мы используем только определённые компоненты Bootstrap-Vue
// чтобы сделать сборку легче
Config.bootstrapVue.componentPlugins = ['LayoutPlugin', 'ImagePlugin', 'LinkPlugin']

// Файл должен вернуть массив с настройками
export default Config

Логика точно такая же, как при расширении классов PHP - импортируем что нужно, меняем и возвращаем.

Команды приложения

До сих пор все команды мы запускали через composer, но на самом деле это просто такой shortcut, ссылка.

Например composer node:generate делает переход во frontend и запускает там yarn generate:admin и yarn generate:site.

Все доступные команды прописаны в package.json и мы вполне можем вызывать их самостоятельно из директории frontend. Давайте посмотрим, что там есть для приложения site:

  • analyze:site - сборка приложения для анализа входящих в него пакетов и занимаемого ими места. Очень полезная штука, если вы не хотите раздувать своё приложение.
  • dev:site - запуск приложения в режиме "для разработки", открывается локальный nuxt сервер, который обновляет страницы при изменении исходных файлов. Так называемый hot reload, очень удобно
  • build:site - сборка приложения для продакшена в директорию frontend/.nuxt/site
  • generate:site - генерация статических файлов для размешения на хостинге без запуска сервера Nuxt, то есть просто набор HTML, JS и CSS
  • start:site - а вот это как раз запуск собранного приложения в серверном режиме с серверным рендерингом, через Process Manager (pm2). Про это будем говорить позже.

Для примера давайте запустим

yarn analyze:site

Если у вас не установлен yarn, то сделайне npm i --global yarn

В браузере должна открыться вот такая чудесная страница со структурой вашего приложения и всеми зависимостями. Она вполне интерактивная и позволяет всё подробно рассмотреть.

Рекомендую время от времени запускать анализ для контроля размера вашего приложения, это очень полезно.

Команда yarn generate:site сгенерирует статические файлы в src/frontend/site, которые будут открыты нашим локальным Valet при помощи драйвера для Vesp.

Структура проекта

Благодаря использованию Nuxt мы всегда имеем одну и ту же структуру приложения, с одинаковыми директориями. Никакой фантазии, понимаю, но в этом случае она и не нужна!

  • assets - наши картинки, стили, шрифты и прочие ассеты, которые будут импортироваться в проект
  • layouts - шаблоны для страниц, как template в MODX
  • pages - собственно страницы приложения, как ресурсы в MODX
  • static - директория со статичными файлами, которые будут размещены в корне собранного приложения. Например, фавиконки.

Nuxt автоматически генерирует структуру сайта исходя из файлов в pages, пока что там один index.vue. При добавлении новых страниц мы получим новые адреса на сайте.

Оформляются они с помощью шаблона frontend/src/site/layouts/default.vue, там обязательно должен быть тег <nuxt /> - именно туда и будет вставлено содержимое страницы.

При навигации по сайту содержимое этого тега меняться будет, а шаблона - нет. Примерно так и получается Single Page Application (SPA), когда весь сайт работает без перезагрузки страницы.

Минутка практики

Давайте запустим разработку сайта в директории frontend:

yarn dev:site

Эта команда запускает локальный сервер Nuxt с горячей перезагрузкой.

после запуска вы видите адрес, по которому доступен сервер. У меня это http://192.168.0.254:4100, но у вас может быть другой - зависит от настроек вашей сети.

Переходим по нему и видим наш текущий сайт.

Теперь идём в frontend/src/site/pages/index.vue. Файл состоит из 3х секций:

  • template - разметка страницы с HTML тегами и компонентами Vue
  • script - javascript код, который будет работать с этой разметкой
  • style - SCSS оформление template

Мы можем просто взять и поменять в style цвет фона страницы на $red - все SCSS переменные берутся из site/assets/_variables.scss и как следствие из Bootstrap:

body {
  background-color: $red;
  color: $gray-500;
}

И вот результат, который вы должны увидеть сразу же, без перезагрузки страницы:

Можно дальше менять страницу и смотреть в браузере, что получается.

Заключение

Думаю, для одного занятия инфорации пока достаточно, в следующий раз будем рассматривать второе, более сложное приложение - админку.

А потом начнём уже и сами что-то создавать.

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

← Предыдущая заметка
Авторизация в системе
Следующая заметка →
Знакомство с админкой
Комментарии (5)
bezumkinВасилий Наумкин
14.01.2023 02:16

Да, мне тоже нравится Vite и он по умолчанию используется в Vue 3 и Nuxt 3. Более того, он вроде как и создан автором Vue с командой. Но здесь мы изучаем Nuxt 2, и в нём используется Webpack.

Учитывая, насколько всё это удобно интегрировано в Nuxt - разницы особой и нет, просто читаешь документацию по настройкам нужной версии Nuxt и всё передаётся в её бандлер.

bezumkinВасилий Наумкин
28.04.2023 10:12

[ всё локально разрабатываю, запускать analyze на удалённом сервере и настраивать для него Nginx ни разу не пробовал.

bezumkin
Василий Наумкин
01.03.2024 04:30
С PWA пока не разбирался, мне кажется это не особо популярная штука. Если надо просто иконки добавит...
bezumkin
Василий Наумкин
22.02.2024 09:23
На здоровье! Держи лайк =)
inetlover
Александр Наумов
27.01.2024 00:06
Василий, спасибо! Извини, тупанул.
bezumkin
Василий Наумкин
22.01.2024 04:43
Давай-давай!
bezumkin
Василий Наумкин
24.12.2023 11:26
Спасибо!
bezumkin
Василий Наумкин
27.11.2023 02:43
Ура!
bezumkin
Василий Наумкин
25.11.2023 08:30
Vesp тянет 2 зависимости: vesp-frontent для фронта и vesp-core для бэкенда. Их можно обновлять, но э...
bezumkin
Василий Наумкин
22.11.2023 08:09
Отлично, поздравляю!
bezumkin
Василий Наумкин
04.11.2023 10:31
На здоровье!
bezumkin
Василий Наумкин
30.10.2023 01:21
Спасибо!