[VESP] Заготовка для SPA сервисов с REST API
Привет, друзья!
Наверное, вы уже обратили внимание, что я не был особо активен в этом году в сообществе. Причина в том, что я набрал кучу работы, с которой смог разобраться вот только что. И работа эта с MODX была никак не связана — я писал собственное решение для сложных проектов, с нуля.

И вот сейчас я готов с вами им поделиться. Но для начала пара важных предостережений:
Во-первых, это не готовое решение, не CMS. Это заготовка для старта нового проекта, в которой уже сделана основная структура.
Во-вторых, она не следует всем модерновым техникам, например используется устаревший паттерн Service Locator. А запросы обрабатывают процессоры через единую точку входа, а не контроллеры с прописанными маршрутами.
Это всё потому, что я из мира MODX, и лично мне так привычно и удобно. Соответственно, когда я придумывал систему «для себя», я сделал так, чтобы было удобно именно мне. Так что, когда вас посетит ощущение «где-то я уже это видел» — так и есть, вы видели это в MODX.
Ну а теперь, если вы готовы, знакомьтесь с VESP:
— Vue.js ( + Nuxt.js)
— Eloquent ORM
— Slim3 micro-framework
— Phinx migrations
В результате мы получаем самую модную сегодня систему с полным разделением фронтенда от бэкенда. Когда и сайт, и другие будущие сервисы шлют запросы в API.
При этом сервер даже не знает, кто именно с ним работает, все запросы рассматриваются как инородные, поэтому нет никаких специальных условий для фронтенда или привилегированных костылей, как это часто бывает в других системах.
1. Клонируем репозиторий VESP на хостинг
2. Переходим в core и переименовываем .env.dist в .env
3. Меняем настройки в .env — нужно указать адрес для запросов в API, подключение к БД и всё такое
4. Запускаем composer install
5. Запускаем ./vendor/bin/phinx migrate — это создаст стандартные таблицы для юзеров
6. Запускаем ./vendor/bin/phinx seed:run — это создаст стандартные записи в таблицах
Серверная часть готова, дальше фронтенд. Его можно разрабатывать на хостинге, или локально. Лично я предпочитаю локально, поэтому:
1. Клонируем репозиторий себе на комп
2. Скачиваем .env с хостинга, или меняем локально — нам нужна настройка SITE_URL
3. Идём в директорию frontend и делаем там npm install && npm run dev
Если всё сделали верно, то запустится локальный сервер разработки по адресу localhost:5112. Открываем его в браузере и проверяем, чтобы запросы уходили на хостинг — там их должно ловить ядро и отвечать. По умолчанию в .env включен параметр CORS, поэтому всё работает с удалёнными запросами.
Все запросы должны прилетать на www/index.php, там прописан единственный маршрут для API.
Дальше срабатывает контроллер core/src/Controllers/Api.php. Его задача — найти запрошенный процессор, загрузить юзера (если он авторизован) и запустить процессор.
Все процессоры находятся в core/src/Processors. В корне директории лежат абстрактные классы для наследования, а во вложенных директориях уже рабочие.
Например, пришёл запрос на api/web/test — значит процессор должен лежать в core/src/Processors/Web/Test.php.
Каждый процессор может отвечать на какой-нибудь тип запроса, то есть иметь методы post, put, patch, delete. Каким методом запрос пришёл — такой метод внутри процессора и дёргается. Если процессор должен только что-то отдавать, и метода put там просто нет, то на запрос put будет ошибка.
Проверка прав реализована свойством scope. Если там что-то есть, то этот scope будет проверяться у группы авторизованного пользователя. Причём, у группы может быть как полный scope на действие, например users, так и только на определённые методы — users/get.
Для работы используются модели Eloquent, пишутся они вручную. Таблицы создаются через миграции — смотрите как сделаны таблицы и модели user и user_roles, это понятный пример. Ну и читайте документацию Eloquent, она очень подробная.
Ну и основной класс со всеми сервисами — Container. Он прокидывается в контроллеры и процессоры, позволяя использовать свои сервисы или свойства, например обращаться к $this->container->user. Да-да, совсем как $this->modx->user.
Это я уже рассказывал в заметке про Nuxt.js.
Но в VESP сразу из коробки подключены нужные модули и настроена авторизация в админку. Так же есть и страницы для работы с пользователями и группами, включая выдачу им нужных scope. Для оформления используется замечательный BootstrapVue с кучей готовых компонентов.
Обратите внимание и на мои компоненты (они лежат в директории components) для простой реализации грида с модальными окнами создания, редактирования и удаления. Всё как в нежно любимом нами ExtJS менеджере MODX.

Для авторизации используется @nuxtjs/auth, работает она через токены. Причём, токены пишутся в БД на сервере, чтобы можно было ограничить количество одновременных подключений и отозвать их у отключенного пользователя. Это очень частый вопрос при работе с токенами, так что я включил его в базовый функционал — смотрите метод Container::makeToken().
После окончания локальной разработки собираем проект через npm run build и выгружаем на сервер. Я всё храню прямо в директории frontend в корне, а запросы разруливает Nginx.
VESP вряд ли будет интересна продвинутым разработчикам, но зато может серьёзно продвинуть начинающих. Вы сможете создать проект любой сложности, с интегрированной админкой, которая не является чем-то инородным, а работает как того хочет заказчик.
Понятное дело, что это не для сайтов-визиток и магазинов-однодневок. Это для больших сервисов, типа krafti.ru — где всё сделано с нуля под заказчика, работает очень быстро и выдерживает хорошие нагрузки. Например о том, что на сайте была распродажа и за день прошло более 2000 покупок, я узнал только на следующий день от радостных клиентов — а не как обычно, когда сервер начал тупить.
Это потому, что сервер больше не занимается рендерингом, а обрабатывает только API запросы. Всё оформление рисует браузер посетителя, избавляя сервис от лишней нагрузки.
В общем, технология очень приятная, и позволит вам вырасти над собой, если есть такое желание. Ну и выставлять совсем другой ценник за работу, конечно.
Я понимаю, что заметка довольна сумбурная, но как-то более подробно расписать результат почти года работы у меня нет сил. Это-то выложить собирался почти месяц.
Поэтому пишите вопросы по узким местам, буду отвечать и дорабатывать текст по мере необходимости.
Исходный код — github.com/bezumkin/VESP
Наверное, вы уже обратили внимание, что я не был особо активен в этом году в сообществе. Причина в том, что я набрал кучу работы, с которой смог разобраться вот только что. И работа эта с MODX была никак не связана — я писал собственное решение для сложных проектов, с нуля.

И вот сейчас я готов с вами им поделиться. Но для начала пара важных предостережений:
Во-первых, это не готовое решение, не CMS. Это заготовка для старта нового проекта, в которой уже сделана основная структура.
Во-вторых, она не следует всем модерновым техникам, например используется устаревший паттерн Service Locator. А запросы обрабатывают процессоры через единую точку входа, а не контроллеры с прописанными маршрутами.
Это всё потому, что я из мира MODX, и лично мне так привычно и удобно. Соответственно, когда я придумывал систему «для себя», я сделал так, чтобы было удобно именно мне. Так что, когда вас посетит ощущение «где-то я уже это видел» — так и есть, вы видели это в MODX.
Ну а теперь, если вы готовы, знакомьтесь с VESP:
— Vue.js ( + Nuxt.js)
— Eloquent ORM
— Slim3 micro-framework
— Phinx migrations
В результате мы получаем самую модную сегодня систему с полным разделением фронтенда от бэкенда. Когда и сайт, и другие будущие сервисы шлют запросы в API.
При этом сервер даже не знает, кто именно с ним работает, все запросы рассматриваются как инородные, поэтому нет никаких специальных условий для фронтенда или привилегированных костылей, как это часто бывает в других системах.
Быстрый старт
1. Клонируем репозиторий VESP на хостинг
2. Переходим в core и переименовываем .env.dist в .env
3. Меняем настройки в .env — нужно указать адрес для запросов в API, подключение к БД и всё такое
4. Запускаем composer install
5. Запускаем ./vendor/bin/phinx migrate — это создаст стандартные таблицы для юзеров
6. Запускаем ./vendor/bin/phinx seed:run — это создаст стандартные записи в таблицах
Серверная часть готова, дальше фронтенд. Его можно разрабатывать на хостинге, или локально. Лично я предпочитаю локально, поэтому:
1. Клонируем репозиторий себе на комп
2. Скачиваем .env с хостинга, или меняем локально — нам нужна настройка SITE_URL
3. Идём в директорию frontend и делаем там npm install && npm run dev
Если всё сделали верно, то запустится локальный сервер разработки по адресу localhost:5112. Открываем его в браузере и проверяем, чтобы запросы уходили на хостинг — там их должно ловить ядро и отвечать. По умолчанию в .env включен параметр CORS, поэтому всё работает с удалёнными запросами.
Как работает ядро
Все запросы должны прилетать на www/index.php, там прописан единственный маршрут для API.
$app->any('/api[/{name:.+}]', function ($request, $response, $args) use ($container) {
$container->request = $request;
$container->response = $response;
return (new Api($container))->process($request, $response, $args);
});
Дальше срабатывает контроллер core/src/Controllers/Api.php. Его задача — найти запрошенный процессор, загрузить юзера (если он авторизован) и запустить процессор.
Все процессоры находятся в core/src/Processors. В корне директории лежат абстрактные классы для наследования, а во вложенных директориях уже рабочие.
Например, пришёл запрос на api/web/test — значит процессор должен лежать в core/src/Processors/Web/Test.php.
Каждый процессор может отвечать на какой-нибудь тип запроса, то есть иметь методы post, put, patch, delete. Каким методом запрос пришёл — такой метод внутри процессора и дёргается. Если процессор должен только что-то отдавать, и метода put там просто нет, то на запрос put будет ошибка.
Проверка прав реализована свойством scope. Если там что-то есть, то этот scope будет проверяться у группы авторизованного пользователя. Причём, у группы может быть как полный scope на действие, например users, так и только на определённые методы — users/get.
Для работы используются модели Eloquent, пишутся они вручную. Таблицы создаются через миграции — смотрите как сделаны таблицы и модели user и user_roles, это понятный пример. Ну и читайте документацию Eloquent, она очень подробная.
Ну и основной класс со всеми сервисами — Container. Он прокидывается в контроллеры и процессоры, позволяя использовать свои сервисы или свойства, например обращаться к $this->container->user. Да-да, совсем как $this->modx->user.
Как работает фронтенд
Это я уже рассказывал в заметке про Nuxt.js.
Но в VESP сразу из коробки подключены нужные модули и настроена авторизация в админку. Так же есть и страницы для работы с пользователями и группами, включая выдачу им нужных scope. Для оформления используется замечательный BootstrapVue с кучей готовых компонентов.
Обратите внимание и на мои компоненты (они лежат в директории components) для простой реализации грида с модальными окнами создания, редактирования и удаления. Всё как в нежно любимом нами ExtJS менеджере MODX.


Для авторизации используется @nuxtjs/auth, работает она через токены. Причём, токены пишутся в БД на сервере, чтобы можно было ограничить количество одновременных подключений и отозвать их у отключенного пользователя. Это очень частый вопрос при работе с токенами, так что я включил его в базовый функционал — смотрите метод Container::makeToken().
После окончания локальной разработки собираем проект через npm run build и выгружаем на сервер. Я всё храню прямо в директории frontend в корне, а запросы разруливает Nginx.
if ($request_uri ~ ".*/$") {
rewrite ^/(.*)/$ /$1 permanent;
}
location ~ ^/api/(.*)$ {
rewrite ^/api/(.*)$ /index.php?q=$1;
}
location / {
root /home/vesp/frontend/dist/;
try_files $uri /200.html;
}
location ~* ^.+\.(jpg|jpeg|gif|css|png|js|ico|bmp|ttf|woff|woff2|svg)$ {
root /home/vesp/frontend/dist/;
access_log off;
log_not_found off;
expires 10d;
break;
}
Собственно, и собираю я фронтенд после разработки тоже на сервере, так быстрее.Заключение
VESP вряд ли будет интересна продвинутым разработчикам, но зато может серьёзно продвинуть начинающих. Вы сможете создать проект любой сложности, с интегрированной админкой, которая не является чем-то инородным, а работает как того хочет заказчик.
Понятное дело, что это не для сайтов-визиток и магазинов-однодневок. Это для больших сервисов, типа krafti.ru — где всё сделано с нуля под заказчика, работает очень быстро и выдерживает хорошие нагрузки. Например о том, что на сайте была распродажа и за день прошло более 2000 покупок, я узнал только на следующий день от радостных клиентов — а не как обычно, когда сервер начал тупить.
Это потому, что сервер больше не занимается рендерингом, а обрабатывает только API запросы. Всё оформление рисует браузер посетителя, избавляя сервис от лишней нагрузки.
В общем, технология очень приятная, и позволит вам вырасти над собой, если есть такое желание. Ну и выставлять совсем другой ценник за работу, конечно.
Я понимаю, что заметка довольна сумбурная, но как-то более подробно расписать результат почти года работы у меня нет сил. Это-то выложить собирался почти месяц.
Поэтому пишите вопросы по узким местам, буду отвечать и дорабатывать текст по мере необходимости.
Исходный код — github.com/bezumkin/VESP
Комментарии: 48
Мало, что понял… но очень интересно! )
Я как «Начинающий» Захотел «Пощупать».
Но думаю, на подобные вещи рано заглядываться…
Я как «Начинающий» Захотел «Пощупать».
Но думаю, на подобные вещи рано заглядываться…
Вот это неожиданно!!! Называется к концу рабочего дня решил на modx.pro зайти, а тут Василий жгёт?
Это для больших сервисов, типа krafti.ru — где всё сделано с нуля под заказчика, работает очень быстро и выдерживает хорошие нагрузки.Нативная интеграция в статью))))
Могу и промокод подогнать со скидкой 10%, если нужно =)
Один вопрос, почему не ларавель или люмен?
Они навязывают свой подход, который мне не нравится.
А вот то, что нравится — Eloquent, я с большим удовольствием использую.
А вот то, что нравится — Eloquent, я с большим удовольствием использую.
На удивление, Eloquent — это почти единственное, что в ларе постоянно критикуют и советуют всем использовать доктрину
Ровно по одной причине — несоответствие принципам SOLID. Eloquent реализует ActiveRecord шаблон, а Doctrine — DataMapper. Последний в отличие от первого реализует принципы SOLID как и Ларавел.
Но лично меня это несоответствие ни разу не напрягает. Eloquent очень удобен. Как и Лара )
Но лично меня это несоответствие ни разу не напрягает. Eloquent очень удобен. Как и Лара )
интересно. Тем более что сам пытаюсь построить что-то похожее.
Выбрал связку
— slim4
— twig
— orm doctrine
— jquery (поскольку очень слаб в нативном js и vuejs)
Выбрал связку
— slim4
— twig
— orm doctrine
— jquery (поскольку очень слаб в нативном js и vuejs)
Это потому, что сервер больше не занимается рендерингом, а обрабатывает только API запросы. Всё оформление рисует браузер посетителя, избавляя сервис от лишней нагрузки.А разве в Nuxt.js не рендерятся страницы на стороне сервера, чтобы получить разные URL на выходе?
UPD. Понял… речь идет об отрисовке. Хотя обычный HTML + JS тоже рендерится браузером не?
Даже при включенном серверном рендере ты грузишь только одну страницу, а дальше всё работает у тебя в браузере — все адреса, переходы, всё. Пока снова не обновишь страницу вручную.
Вот открой тот же krafti.ru, включи консоль и посмотри на запросы при переходе по разделам сайта. Там как раз работает серверный рендеринг.
HTML никакой не грузится, только картинки и данные JSON.
Вот открой тот же krafti.ru, включи консоль и посмотри на запросы при переходе по разделам сайта. Там как раз работает серверный рендеринг.
HTML никакой не грузится, только картинки и данные JSON.
Последнее время много попадается информации о том что это мол очень быстро, сервер обрабатывает только апи запросы, возвращает json, а браузер пользователя все отрисовывает.
А кто-то пробовали это на чем-то высоконагруженном?
krafti.ru/ мне кажется не показателен, это ведь практически лендинг.
А кто-то пробовали это на чем-то высоконагруженном?
krafti.ru/ мне кажется не показателен, это ведь практически лендинг.
Это, как бы, онлайн магазин по продаже курсов и просмотру с полным функционалом — типа отправки домашних работ, комментариев и т.д. Но увидеть это можно только после покупки курса.

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


Запустились 11 сентября, с тех пор уже несколько тысяч заказов и ни одной проблемы. Не знаю, как для тебя, а мне этого вполне достаточно для выводов.
а если весь рендеринг теперь лежит на браузере пользователя интересен такой момент, на сколько при таком взаимодействии съедаются ресурсы системы, и насколько должна быть слабая машина, чтобы всё подвисло))
Я бы не стал сильно об этом переживать… Если разработчик более менее с головой, то будет шустрее чем с jquery))) Вебпак об этом позаботится
Не совсем понял, причем тут вебпак и отрисовка с обработкой данных на стороне клиента?
Будете сильно удивлены, но www.ozon.ru/ работает на nuxtJs
Интересно как они решали вопрос с seo
там довольно таки просто, все сео обрабатывается на стороне сервера.
Надо уже привыкнуть что js работает как обычный php за счет nodejs. А потом тот же js работает как js в привычном понимании уже после загрузки страницы.
Надо уже привыкнуть что js работает как обычный php за счет nodejs. А потом тот же js работает как js в привычном понимании уже после загрузки страницы.
Я просто думал, что контент страницы без обработки js в json приходит отдельно, а уже потом скрипты js парсят json и наполняют html-скелет данными. Это было бы для роботов не очень здорово. А сейчас получше посмотрел, и вижу html-теги с контентом в исходном коде, всё как положено. Но как-то странно, один и тот же текст и в тегах и в json. Короче, пока непонятно как это всё работает)
Прочитайте про то как работает nuxt.js и как это решает эту проблему, Наумкин как раз недавно выкладывал статью про это modx.pro/development/18695
Для этого есть серверный рендеринг
Магазинус Лебедева тоже на nuxt
Это прекрасное решение! Я бы сказал дает прям «глоток свежего воздуха» в серые, обыденные будни!
Спасибо!
Спасибо!
Я пока не смотрел исходники, но сразу появился вопрос: для чего использовать SLIM который на php если используется nuxt который на nodejs. Почему вместо слима не используется тот же node?
nuxt собирает приложение, используя node js. Бэкенд может быть любым.Главное иметь API к которому будет обращаться приложение на js.
Гениально, правда это я и сам знаю, я спросил «для чего использовать SLIM...», уточню, чтоб понятнее был вопрос: на хрен использовать PHP если на сервере крутится NODEJS??? Ради Phinx migrations, наработкам, привычке или что еще?
Не всегда крутится у меня на сервере NodeJS, я стараюсь в статику сгенерировать страницы и дальше отдавать их через Nginx.
А даже если и крутится, писать бэкенд на PHP мне гораздо приятнее и привычнее. Eloquent, опять же, не на JS написан.
А даже если и крутится, писать бэкенд на PHP мне гораздо приятнее и привычнее. Eloquent, опять же, не на JS написан.
Спасибо, теперь понятно.
Чет у меня картинки с крафти ползут по 13 и более секунд. Да и вообще размер их больше чем требуется.
Спасибо за такое крутое решение! Очень интересно было почитать.
Василий, есть ли планы вообще уйти от php в сторону node.js?
Интересно узнать, что ты думаешь по этому поводу.
Василий, есть ли планы вообще уйти от php в сторону node.js?
Интересно узнать, что ты думаешь по этому поводу.
Нет таких планов, PHP мне нравится больше.
А на днях посмотрел новинки версии php7.4 так и вообще пришел к выводу, что php и javascript становятся даже по синтаксису близки. В 7,4 появились стрелочные функции, оператор… для объединения массивов.
Интересно. Я подобное делал на Laravel. Вот думаю, не слишком ли это большой оверхед по сравнению с вашим вариантом?
Думаю, большой.
Я даже в Slim3 использую только самые базовые классы Response и Request, даже без middlewares.
Я даже в Slim3 использую только самые базовые классы Response и Request, даже без middlewares.
С другой стороны, любой хостинг тянет без особых проблем Laravel. Bроде всё есть. Пользователи, middleware, eloquent. Для меня, как любителя пойдет.
Надо писать обучающий курс. Хотя бы как пример как Sendex был курс. Чтобы народ начал въезжать.
Насколько сложно выпилить Vue и поставить React?
Ты серьёзно думаешь, что я выпиливал Vue и ставил React?
Без понятия. Попробуй и расскажи нам.
Без понятия. Попробуй и расскажи нам.
Да я думаю можно просто очистить папочку frontend и подсмотреть в конфиг чтобы настроить тот же Next/Gatsby
Да, спасибо, я глянул исходники, в принципе ничего сложного.
Правда, пока смотрел — понял, что мне не пригодится такая заготовка, даже с Реактом на борту.
Правда, пока смотрел — понял, что мне не пригодится такая заготовка, даже с Реактом на борту.
Все равно не понятно, как эти VUE, NUXT дружат с сео
Василий, ты просто не заморачивался с description под поисковики, или это особенности такого подхода?
Василий, ты просто не заморачивался с description под поисковики, или это особенности такого подхода?

Есть server side rendering и насколько я понимаю, поисковику без разницы кто отдает отрисованную страницу. По этому с сео проблем точно не должно быть.
Спасибо,
Почитаю
Почитаю
Вместо сервер сайд рендеринга в больших проектах делают версию для поисковиков. Весь смысл применения реактивных фреймворков ломается о сервер сайд рендеринг
Каким образом она ломается?
Василий, привет! Спасибо за заготовку. Развернул у себя. Буду экспериментировать.
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.