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

Как вы уже поняли по предыдущим заметкам, бэкенд и фронтенд 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 комментариев

Алексей
Я, как старый страпёр, собираю всё ещё на gulp'е (при чём, меня он устраивает, но у меня там всё для modx заточено), а тут оказывается уже webpack'ом народ пользуeтся! Однако, закинул удочку своему корешу по веб-разработке, и он советует сразу использовать vite, минуя вебпак - мол проще разбраться, и бытрей работает. Кто-нибудь пробовал его на vesp? или, не стоит заморачиваться, и работать просто с webpack'ом?
Василий Наумкин
Да, мне тоже нравится Vite и он по умолчанию используется в Vue 3 и Nuxt 3. Более того, он вроде как и создан автором Vue с командой. Но здесь мы изучаем Nuxt 2, и в нём используется Webpack.
Учитывая, насколько всё это удобно интегрировано в Nuxt - разницы особой и нет, просто читаешь документацию по настройкам нужной версии Nuxt и всё передаётся в её бандлер.
Для примера давайте запустим
yarn analyze:site
Это видимо работает только на локалке? У меня VESP на VPS висит и там после этой команды что-то формируется, но эту страницу на реальном домене открыть не получается. Или же нужно дополнительно настраивать пути сервера, для выполнения этой команды? Ну если это вообще нужно.
Василий Наумкин
[ всё локально разрабатываю, запускать analyze на удалённом сервере и настраивать для него Nginx ни разу не пробовал.
Ок, понял, спасибо
bezumkin.ru
Personal website of Vasily Naumkin
Прямой эфир
Василий Наумкин
01.07.2024, 11:56:41
Да, верно, именно так. А в контроллере, скорее всего, ловить данные методом post.
Василий Наумкин
26.06.2024, 09:38:15
О, точно, вылезает если не залогинен. Спасибо, исправил!
Василий Наумкин
09.04.2024, 04:45:01
> Ошибка 500 Это не похоже на ошибку Nginx, это скорее всего ошибка PHP - надо смотреть его логи. ...
Futuris
04.04.2024, 08:56:12
Я просто немного запутался. Когда в абзаце "Vesp/Core" ты пишешь про "новый trait FileModel", я поду...
Василий Наумкин
20.03.2024, 21:21:52
Volledig!
Андрей
14.03.2024, 13:47:10
Василий! Как всегда очень круто! Моё почтение!
russel gal
09.03.2024, 20:17:18
> А этот стоило написать хотя бы затем, чтобы получить комментарий от юзера, который ничего не писал...
Александр Наумов
27.01.2024, 03:06:18
Василий, спасибо! Извини, тупанул.
Василий Наумкин
22.01.2024, 07:43:20
Давай-давай!
Василий Наумкин
24.12.2023, 14:26:13
Спасибо!