Совершенно неожиданно вышла новая версия Vesp - 3.0.
Как известно, Vesp состоит из Vue, Eloquent, Slim и Phinx. 3 части названия состовляет PHP бэкенд (пакет vesp/core), оставшаяся 1 часть - это фронтенд на Vue (пакет @vesp/frontend).
В новой версии обновлены они оба, но фронтенду досталось сильно больше из-за перехода на Vue 3.
Минимальная версия теперь PHP 8.1, прекрасно поддерживается и текущая стабильная 8.3.
Зависимости обновлены до последних версий: Eloquent 10, JWT 6, PhpUnit 10.
Во всех классах, где это возможно, добавлены типы переменным. Например, было так
abstract class ModelController extends Controller
{
/** @var string $model */
protected $model;
protected $primaryKey = 'id';
protected $maxLimit = 1000;
А стало вот так
abstract class ModelController extends Controller
{
protected string $model;
protected string|array $primaryKey = 'id';
protected int $maxLimit = 1000;
Если вы будете обновлять на новую версию старый проект, то IDE вам обязательно должно подчеркнуть ошибки в старых контроллерах и моделях - просто укажите правильные типы, ничего сложного.
Для более удобного расширения контроллеров создан отдельный метод инициализации. Раньше для переопределения основного метода __invoke
надо было прописывать кучу всего обязятельного, и только где-то в конце менять нужное, а теперь вот так:
class MyController extends Controller
{
public function __invoke(RequestInterface $request, ResponseInterface $response): ResponseInterface
{
// Выставление $this->request, $this->response, $this->route, $this->user
// и свойств, доступных через $this->getProperties()
$this->initController($request, $response);
// Дальше ваша особенная логика
}
}
Контроллеры теперь отдают не красиво распечатанный JSON, а обычный в одну строку - так расходуется меньше трафика на ответы от сервера. Флаг JSON_PRETTY_PRINT
в ответах заменён на JSON_THROW_ON_ERROR
.
В контроллере изображений добавлена поддержка композитного ключа. Везде эта поддержка была, а в картинках почему-то не было.
Добавил поддержку нового имени для куки авторизации auth:token
, старая auth._token.local
тоже осталась. Она была от фронтового пакет @nuxtjs/auth
, в новой версии фронтенда его нет, так что имя куки стало проще.
Очень много изменений было в работе с файлами. Основное отличие - теперь файловые методы привязаны не к файловой системе, а к собственно модели, через новый trait FileModel
.
Все методы, типа uploadFile
, getFile
, getSaveName
теперь в нём, а значит, что вы можете создать сколько угодно моделей для разной логики работы с файлами.
Файловая система может быть одна, а вот логика наименования файлов в ней зависеть от модели. Лично мне так кажется гораздо более удобно и логичнее.
Добавлена композитная модель UserFile
, как пример использования нового трейта. Довольно часто в проектах нужно загружать какие-то файлы юзерам, так что лишним не будет.
Улучшена работа с большими файлами: и загрузка и отдача. Автоматическое получение размеров картинок теперь работает только для файлов <= 50 мегабайт.
composer.json
и composer.lock
переехали внутрь директории core
. Раньше были снаружи, что как-то не согласуется с полным разделением бэкенда и фронтенда.
Тесты теперь можно быстренько прогнать через Docker.
git clone https://github.com/bezumkin/vesp-core.git
cd ./vesp-core
docker-compose up
Вам это не нужно, а мне приятно.
Здесь было гораздо больше изменений, благодаря переходу на:
Благодаря новому композитному синтаксису пришлось переписать вообще всё. Плюс, для нового Nuxt нет многих старых привычных модулей, например авторизации и подключения Font Awesome - и мне пришлось написать их самостоятельно.
Как и раньше, @vesp/frontend
является модулем для Nuxt, нужно просто подключить его и указать настройки. Работает поддержка типов, всё экспортируется, подсказки в IDE вам помогут:
Благодаря новым возможностям Nuxt больше нет разделения на 2 приложения: admin и site. Админка теперь это просто вложенные странички сайта, которые не рендерятся на сервере. А весь остальной сайт рендерится.
Соответственно, нет нужды и запускать 2 процесса Nuxt через concurrently
- меньше тратится ресурсов.
Я крайне не советую обновлять старые проекты на новую версию, это равносильно переписыванию всего с нуля. Если, конечно, именно такой задачи у вас и не стоит.
Bootstrap Vue Next сейчас в очень активной разработке, и похоже будет там еще долго. Но я всё равно смог с ним подружиться и наладить нормальную работу. Поэтому версия пакета будет жёстко фиксироваться, чтобы он сам не обновлялся и не ломал уже работающее.
Я постарался, как мог, прописать поддержку собственных типов Vesp, вы увидете это в исходниках. Рекомендую пользоваться, чтобы делать меньше ошибок.
Typescript не является обязательным, он не участвует в компиляции и его ошибки ни на что не влияют, они должны просто помогать вам писать более правильный код.
SCSS файлы так же экспортируются модулем, вы можете их легко подключить в своих стилях:
@import 'bootstrap-scss/bootstrap';
@import '@vesp/frontend/assets/components';
@import '@vesp/frontend/assets/toast';
@import '@fortawesome/fontawesome-svg-core/styles.css';
Понятное дело, что там всё завязано на Bootstrap и вы можете переопределить переменные SCSS.
На данный момент модуль добавляет следующие компоненты:
vesp-table
- компонент для вывода таблиц админкиvesp-modal
- модалка с поддержкой отправки форм и обновления соответствующей таблицыvesp-fa
- иконки FontAwesomevesp-change-locale
- компонент для переключения языкаvesp-input-alias
- компонент для ввода адресов страниц, использует slugify
vesp-input-combo-box
- ввод с автодополнением через запросы к APIvesp-input-date-picker
- ввод даты или диапазона дат, использует vue-datepicker-next
vesp-input-password
- ввод пароля с кнопочкой "показать\скрыть"vesp-input-remote-links
- ввод JSON массива "название сервиса-адрес", например для ссылок на соцсетиvesp-input-text-mask
- ввод телефонов или других данных по маске, использует text-mask-core
В основном эти компоненты расширяют что-то из BootstrapVue.
Также есть разные полезные функции:
useGet
, usePost
, usePut
, usePatch
, useDelete
- простые запросы в API с поддержкой авторизации и безо всяких наворотов, вроде сохранения состояния и кэширования.useApi
- тоже самое, но с возможностью более тонкого указания параметров - функции выше используют эту функцию внутри себяuseCustomFetch
- а это как раз запрос в API со всеми наворотами, плюс поддержка авторизации. Подробнее читать в документации Nuxttry {
const data = await useGet('user/profile')
console.log(data)
} catch (e) {
console.error(e)
}
Дальше работа с авторизацией через композит useAuth
:
const {loggedIn, token, user, login, logout, loadUser, setToken} = useAuth()
console.log(loggedIn.value, user.value, token.value)
Экспортируются переменные:
loggedIn
- computed
переменная со статусом авторизации, внутри true
или false
.token
- ref
на куку с токеном, может быть строкой или undefined
.user
- ref
на юзера, может быть объектом типа VespUser
или undefined
.И полезные функции:
login(username, password)
- авторизацияlogout()
- выход и удаление токена на сервереloadUser()
- загрузка профиля с сервераsetToken(string)
- выставление нового токена в куку авторизацииПростейший пример авторизации:
<template>
<div v-if="loggedIn">
<pre>{{ user }}</pre>
<b-button @click="() => logout()">Logout</b-button>
</div>
<div v-else>
<b-form @submit.prevent="onSubmit">
<b-form-group label="Username">
<b-form-input v-model="form.username" required />
</b-form-group>
<b-form-group label="Password">
<vesp-input-password v-model="form.password" required />
</b-form-group>
<b-button type="submit">Submit</b-button>
</b-form>
</div>
</template>
<script setup lang="ts">
const {loggedIn, user, login, logout} = useAuth()
const form = ref({username: '', password: ''})
async function onSubmit() {
try {
await login(form.value.username, form.value.password)
form.value = {username: '', password: ''}
} catch (e) {
console.error(e)
}
}
</script>
Дальше функции по выводу всплывающих сообщений:
useToastInfo(message, options)
useToastSuccess(message, options)
useToastError(message, options)
useToastsClear()
- убирает выведенные сообщенияВсё понятно из названий. Первым параметром идёт сообщение, вторым можно указать дополнительные опции для вывода.
Если при запросе в API произошла ошибка, она будет выведена автоматически через useToastError()
.
Есть еще полезные функции:
getApiUrl()
- определяет базовый адрес для запроса в APIgetImageLink(VespFile, VespFileOptions)
- формирует ссылку на вывод картинки из API, принимает переменные указанных типовusers/get
Скорее всего, список всяких полезных функций еще будет расширяться.
Самое прикольное, что ничего импортировать не нужно: ни компоненты, ни функции, ни авторизацию. Оно всё просто доступно во всех vue
файлах, за это отвечает Nuxt.
Новая версия рассчитана на работу в Docker. По умолчанию прописан production
конфиг, который вы можете переопределить файлом docker-compose.override.yml
.
Я приложил в комплект такой файлик с расширением dist
, его можно переименовать и запускать контейнеры в режиме для разработки. Разница, в общем-то, только в открытии внешних портов, но вы можете переопределить и что-то еще.
Также упростил файл .env
и прописал умолчания в docker-compose.yml
, теперь из настроек для Docker только хост Nginx и возможность установить Xdebug в PHP.
В общем, никаких раздельных конфигов, всё оптимизировано и упрощено.
Новая версия теперь по умолчанию в репозитории, запустить новый проект проще простого.
git clone https://github.com/bezumkin/vesp.git
cd vesp
cp .env.dist .env
cp docker-compose.override.yml.dist docker-compose.override.yml
docker-compose up --build
Если у вас уже есть проект с названием vesp
в докере, нужно указать новое имя в .env
перед запуском, например:
COMPOSE_PROJECT_NAME=vesp-new
Миграции и сиды теперь накатываются при первом же старте, никаких лишних телодвижений.
Дожидаемся в консоли надписи Vite client warmed up in
, открываем 127.0.0.1:8080
и входим в админку, используя логин и пароль admin.
Все свои новые проекты я буду делать на этой версии, так что будут еще разные правки по мере нахождения проблем.
Василий, добрый день!
Когда выполняю команды в такой последовательности:
Получаю ошибку:
Когда в такой:
Все встает и работает.
Да, только вот строк** Vite client warmed up in** в консоли я не дождался, загрузка остановилось на:
Отсюда и в админку не попал.
То, что этих строк нет - это логично, потому что нет файла
docker-compose.override.yml
и фронт запустился в production режиме, а не в режиме разработки.Но сайт всё равно должен работать по адресу
127.0.0.1:8080
:Возможно, у тебя другая версия Docker, но решается это просто. Нужно поменять все
на
То есть, сделать их строками. Внёс это исправление в репозиторий.
Если что, у меня такая версия
Разобрался, почему у тебя была ругань не на строки в конфиге. Это потому, что используется старая версия docker-compose v1, когда он еще был отдельным приложением на Python.
С версии 2 он встроен в Docker и вызывается как
docker compose
- то есть через пробел, теперь это внутренняя команда самого докера.У меня на MacOS работает и так и эдак - у обеих команд версии 2+, а вот на Ubuntu нет. Более того, официальная инструкция по установке докера предлагает отдельный
docker-compose
и вовсе удалить.А еще есть возможность создать ссылку для совместимости:
Буду менять свои инструкции на новый формат команд.
Василий, и еще просьба, добавь в инструкцию, как открыть порт для БД в режиме разработки.
Но в принципе и не помешало бы подружить с phpMyAdmin даже на сервере, хотя бы иметь инструкцию, как это безопасно сделать, мало ли если пойдет что-то не так, когда добавляешь свои наработки в рабочий проект и приходится вмешиваться. Конечно VESP не так, как MODX завязан на БД, но привычка то осталась )).
Для этого и придуманы миграции. Тестируешь всё локально и в продакшене они так же работают. Смысл переходить на Docker, если ты на живом сервере собираешься что-то делать?
Это же главная фишка, что у тебя локально и на сервере одна и та же система, которая ведёт себя одинаково.
PhpMyAdmin просто некуда подключаться, в рабочем режиме открыт только порт 8080, а БД изолирована. К ней можно подключиться только через консоль докера:
Василий, спасибо! А за это:
docker exec -ti имяконтейнера mariadb -uvesp -pvesp vesp
- отдельное спасибо!Я это все прекрасно понимаю и благодаря тебе сейчас пытаюсь всему этому научится )).
Василий, добрый день! Спасибо!
Решил данную проблему полной переустановкой Докера, видимо была сильно старая версия.
Сейчас у меня проблема с входом в админк. Дождался в консоли появления Vite server warmed up in 32919ms и пошел смотреть админку http://127.0.0.1:8080/admin, а там ошибка 401:
А в консоли ошибка 404 не может обнаружить файл Service Worker:
Василий, с этой проблемой разобрался.
Но сейчас не пускает в админку. Пароль принимает, toast показывает приветствие, а больше ничего не происходит.
Попробуй из анонимного режима.
Есть подозрение, что у тебя браузер что-то закэшировал по этому адресу от старых проектов. Не зря же он ищет несуществующий
sw.js
.Спасибо, попробовал разные варианты и браузеры менял но не вышло, буду переустанавливать.
Но вот Орбита встала, как надо и в админку впускает!
Это странно, учитывая, что новый Vesp и сделан на базе Орбиты - я оттуда всё перетаскивал, включая конфиги.
Смотри тогда, что в консоли браузера и докера - должна быть какая-то ошибка. И еще, попробуй всё сделать заново - я вчера закомитил разные улучшения в Vesp, надо обновить исходники.
Если не разберёшься, напиши мне в телеграм, помогу.
Василий, добрый день!
Понял откуда ноги растут, почему не впускает в админку:
Если устанавливаю так, то проблемы нет:
А если так, то в админку не впускает:
Может у меня проблема в установленном Docker, устанавливал его по этой инструкции https://drive.google.com/file/d/1aZxgFjnIFDLTw57jMbIHq7oyK_2xi6Ro/view на Ubuntu 22.04, Docker 24.0.5?
На будущее - Docker нужно ставить по инструкции с официального сайта, так надёжнее.
У тебя, получается, вся разница только в файле docker-compose.override.yml, но я не вижу там ничего такого, что бы могло сломать авторизацию.
Просто открытые порты и
restart: no
сервисам, чтобы они не стартовали автоматически при старте системы. Видимо, дело в том, чтоfrontend
запускается вdevelopment
режиме и что-то не работает.Сейчас попробую загрузиться с Ubuntu Live USB и там проверить.
Поставил Ubuntu 22.04.3 LTS на внешний HDD (офигел от тормозов, конечно, после SSD) и всё у меня заработало.
Контейнер с
node
запустился только со второго раза, первый разyarn
выдавал ошибкуENOSYS Function not implemented
. Второй раз всё ок. Ну и разрешения наupload
иtmp
указал777
.Авторизация работает в режиме разработки, всё хорошо.
Спасибо!
Я еще сразу же после запуска получаю ошибку 500 и только после Ctrl + F5 я могу видеть кнопку входа.
Буду дальше пробовать, переустановлю Докер по оф. инструкции, может версия Docker Compose у меня не подходящая.
В принципе я понял в чем у меня проблема, все дело правах на папки которые создал движок по команде:
docker-compose up --build
.Я не мог авторизоваться, потому что у папки docker/mariadb/ был какой-то загадочный владелец user #999.
Сейчас ставлю в такой последовательности:
После, как все новые папки созданы, устанавливаю на все права 777, а потом:
И вроде все работает как надо.
У меня такой же владелец 999 с группой 999 и это никак не мешает.
Более того, у тебя вроде как на той же машине нет проблем с Орбитой, у которой наверняка те же права на директорию. В общем, мистика.
Спасибо, буду разбираться!
У Орбиты в инструкции не было команды:
cp docker-compose.override.yml.dist docker-compose.override.yml
, отсюда на начальном этапе и проблем не заметил.Василий, а ты команду docker с sudo в Ubunte запускал?
Вроде да, не помню уже.
Если получаешь
access denied
, значит нужно использовать sudo. Если нет - нет.Спасибо!
Если речь идет о WSL - не лишне будет выполнить
У меня тоже не пускало, теперь я команды установки последовательно выполняю. Сначала клонирую репозиторий, потом расшариваю папку tmp и далее запуск. Во всяком случае теперь админка работает.
Только что проверял на Windows с Docker на Hyper-V - и там никаких проблем с разрешениями не было.
Судя по цвету терминала у Александа вообще Ubuntu =)
да, глупость сморозил))
Василий, есть пара вопросов по запуску в Докере. Буду благодарен, если прокомментируешь.
Сначала про production. Как понял, если я не переименовывать файл
docker-compose.override.yml.dist
, то проект запускается в режиме production. Об этом же выводится сообщение -vite v5.0.11 building SSR bundle for production...
В этом случае при запуске не выводится сообщение -Vite client warmed up in ..
. Вместо этого -Listening on http://[::]:3000
. На локалке в этом режиме все запускается и админка работает. Правильно ли я понимаю, что в качестве инструкции по дальнейшей настройке рабочего сервера можно использовать твой пост про запуск Орбиты?Да, верно.
У тебя на сеервере образуется локальный порт
8080
, на который нужно направить Nginx с настроенными сертификатами и правильным доменным именем. Если проектов несколько, то нужно поменять им порты, чтобы не пересекались.У меня, например, все порты от
10000
.Понял, спасибо! А порты меняются в docker-compose.yml -
NGINX_PORT=${NGINX_PORT:-8080}
? А "нодовский" порт 3000 - это чисто внутри Докера? Если у меня на сервере порт 3000 занят - они не пересекаются?docker-compose.yml
менять не нужно, просто укажи новый порт в.env
файлеПорты внутри докера не пересекаются. Если что-то пересечется - увидишь ошибку.
Ок, спасибо! А при запуска в "локальном режиме" (с активированным файлом
docker-compose.override.yml
) у меня почему-то контейнер php-fpm автоматом не запускается вместе с другими контейнерами. Выдает ошибкуphp-fpm-1 exited with code 255
. Правда лечится это элементароно - ручным запуском контейнера. После чего все прекрасно работает. Может особенность Докера в WSL.Посмотри предыдущие сообщения от этого php-from контейнера, может там разгадка.
Может быть, там упоминается об ошибках, но что с этим делать (кроме запуска контейнера вручную) я пока не знаю.
Это значит, что БД не принимает подключение и поэтому контейнер PHP не может выполнить команду и останавливается.
Если ты затем руками его запускаешь и всё хорошо, значит БД просто не успевает запуститься и принять первое подключение от PHP. Почему не успевает - непонятно.
Чтобы такого не было в конфиге докера для
php-fpm
прописана зависимостьМожно попробовать поменять команду на запуск в override файле таким образом:
То есть, добавить таймаут 5 секунд перед попыткой выполнения миграций.
Ну да! Теперь все запускается. Спасибо!
В качестве дополнительной информации опишу "результаты дальнейших тестов".) VESP в нынешней редакции у меня запускается, только если я запускаю его с "дефолтными" значениями DB_DATABASE, DB_USERNAME и DB_PASSWORD - vesp. Звучит как бред, но это факт.)) Т.е. я запускаю единой командой:
Далее чтобы контейнер php-fpm-1 "не брыкался" я добавляю && sleep 5 && в docker-compose.override.yml как ты советовал. В админку пускает, в моем случае по-крайней мере, только после расшаривания прав на папку tmp, что проблемой, разумеется не является. И после этого я запускаю и все ОК.
Но далее, я решил изменить данные DB. Поскольку я не знаю как это сделать в Докере, и можно ли вообще это сделать - я переустановил VESP и изменил значения DB_DATABASE, DB_USERNAME и DB_PASSWORD в .env. Предварительно вычистил Докер. И вот в этом случае php-fpm-1 отказывается работать, даже если добавить && sleep 5 && или запустить его вручную. Причем в обоих режимах - на продакшене то же самое. Выдается ошибка:
SQLSTATE[HY000] [1045] Access denied for user 'vesp3'@'172.19.0.3' (using password: YES)
- vesp3 я проставил значения DB.Ну так а ты поменял настройки БД в файле
.env
? PHP же использует их для подключения, видимо они не совпадают.А зачем тебе их вообще менять? Они не имеют никакого значения: БД внутри докера, закрыта по умолчанию для подключения снаружи. При разработке порт открывается, но это же на локальном компе.
БД изолирована внутри докера, поэтому логин и пароль вообще без разницы, нужны только для подключения соседних контейнеров, таких как PHP.
Конечно поменял. DB_DATABASE, DB_USERNAME и DB_PASSWORD вместо vesp поставил vesp3. А что, эта версия ставится с предустановленными настройками бд, юзера и пароля? Наверное поэтому она и устанавливается командой
docker-compose up --build
, а прошлая - простоdocker-compose up
? Насколько помню в прошлой редакции VESP я мог изменять данные DB.Дело не в том, что мне нужно их менять. Просто я поменял и вижу проблему, а пока еще толком не знаю как правильно нужно работать с Докером. Если менять не нужно и это снимет вопросы - значит и не буду менять. Я просто подумал, а если на сервере у меня будет висеть несколько проектов на VESP - как к базам подключаться из PHPMyAdmin? Короче по-старинке еще мыслю - как будто "не в Докере".)
Открой файл docker-compose.yml - там прописаны все значения по умолчанию. Их можно переопределить, указав в
.env
:Указанные значения в этих переменных должны совпадать.
Ну так может уже пора книжку почитать какую, или видеокурсы посмотреть по Docker?
Никак, в рабочем режиме контейнеры закрыты от подключения снаружи. Можно зайти только через
docker exec -ti имяконтейнера mariadb
Блин вот стыдоба то(( . Замылилась голова от переустановок и в двух конфигах запутался)
Конечно пора. Спасибо большое за помощь!
Василий, добрый день!
Столкнулся с проблемой, что бы изменения вступили в силу, приходится остановить контейнеры и заново их запустить.
Что сделать, что бы стало работать без перезагрузки?
Может быть проблема моя в том, что я работаю без файла docker-compose.override.yml?
Естественно.
Когда у тебя frontend в production режиме - он собран в готовые файлы, которые не меняются от того, что ты поменял их исходники.
Именно для этого и нужен development режим, чтобы было отслеживание изменений и пересборка.
Там же команды разные в yml файлах: или
yarn start
илиyarn dev
- не обратил внимания?Спасибо!!
Василий, возник вопрос, напрямую не связанный с VESP, но может у тебя будет возможность подсказать в каком направлении копать. Я добавил в админку страницу для постов -
frontend\src\pages\admin\posts.vue
. И далее страницу редактирования постов (frontend\src\pages\admin\posts\[id]\edit.vue
) и форму создания -frontend\src\pages\admin\posts\create.vue
.Форма создания поста, по аналогии с
user-roles\create.vue
(содержит тег<forms-user-role v-model="record" />
) иusers\create.vue
(<forms-user v-model="record" />
) должна содержать тег<forms-post v-model="record" />
. Но в таком виде модал не вызывается. Но стоит мне заменить код моей формы на код формы из Орбиты, или просто заменить тег<forms-post v-model="record" />
на<forms-page v-model="record" />
как модал начинает вызываться. Форма, при этом, конечно вызывается без полей, т.к. она никак не связана с моей моделью Post, но модал даже в таком виде работает. И я не могу понять, почему не вызывается модал с моим тегом<forms-post v-model="record" />
? Ведь именно так должно быть правильно. P.S. Добавил картинку с анимацией, как это происходит.Да, так и должно быть. Раз модалка не появляется, значит в твоей форме какая-то ошибка. Открывай консоль браузера и смотри, на что ругается. Без консоли при разработке фронтенда ловить вообще нечего.
Ты сам файл-то создал в
components/forms/post.vue
? С таким кодом компонента модалка работать должна:<template> <div>Привет!</div> </template> <script setup lang="ts"></script>
Ну а дальше добавляй поля формы по образу и подобию. Если сломается - будет понятно, от чего.
На этот сайт можно грузить короткие MP4 видосики.
Файл-то
components/forms/post.vue
у меня был. Я взял за основу файл с Орбиты и переделал под свои поля. Но, очевидно там были ошибки. С твоим "минималистичным" кодом формы модал заработал! Спасибо за помощь! Буду разбираться дальше.Василий, добрый день!
Если есть возможность, перепиши, пожалуйста, кусок кода на Vue 3 в Composition API. Читаю документацию, но пока во многом не разобрался, думаю на этом примере получится быстрее понять как оно устроено.
Примерно так:
const showFullNav = ref() const scrollPosition = ref() function handleScroll() { if (process.client) { const currentScrollPosition = window.scrollY; if (currentScrollPosition < scrollPosition.value) { console.log("Scrolling up"); showFullNav.value = true; } else { console.log("Scrolling down"); showFullNav.value = false; } scrollPosition.value = window.scrollY; } } onMounted(() => { window.addEventListener("scroll", handleScroll) })
Василий, спасибо большое!
Еще пару вопросов:
this в Composition API не используем?
Плагины не нужно регистрировать в nuxt.config.ts?
Именно! Нет никакого
this
в новом синтаксисе, в этом весь смысл - использовать везде функции, не зависящие от контекста исполнения, то есть отthis
.Не нужно, да. Если они лежат в директории
plugins
, то новый Nuxt автоматически их регистрирует. То же самое и сcomponents
.Спасибо, большое, сэкономил мне кучу времени!
Василий, добрый день!
Подключаю модуль в nuxt.config.ts
В итоге ошибка:
Почему-то модуль ищет в пакете Vesp.
Подскажи, пожалуйста, как регистрировать установленный модуль?
Устанавливаю так:
Нет, это путь к зависимостям на диске внутри Docker -
/vesp/frontend/node_modules
. Что-то ты куда-то не туда установил, похоже сделал это не внутри контейнера Docker.Меня настораживает, что ты делаешь
cd /frontend
. Во-первых, это путь от корня твоего диска, а во-вторых - при открытии консоли фронтенда, ты уже должен быть в нужной директории:В любом случае, этот модуль тебе не нужен, потому что
useColorMode
уже есть в BootstrapVue.Лучше использовать его, чтобы не было такого предупреждения:
Да, так точно. Устанавливаю не внутри контейнера vesp-node-1, спасибо, буду знать.
О, за это, спасибо, большое! Так конечно правильнее и легче будет.
Василий, добрый день!
Подключаюсь в тестовом режиме к БД через MySQL Workbench - работает. Хочу просмотреть таблицы - Workbench схлопывается. В файл docker-compose.yml добавил phpMyAdmin
Хочу подключится через него - тоже не выходит.
Подскажи, пожалуйста, в чем может быть проблема. Записал коротенькое видео:
С Workbench я вроде разобрался, хотелось бы еще, ради эксперимента, phpMyAdmin таким способом подключить.
Зачем? Есть же нормальные десктопные приложения для работы с БД, в тот же PhpStorm встроен DataGrip.
Я никогда не ставил PhpMyAdmin в Docker, так что ничего подсказать не могу.
Василий, спасибо, уже так делаю!
Василий, добрый день!
Тебе случайно не встречалась ошибка запрета нижнего подчеркивания в названии css селектора?
Это Stylelint, такие правила прописаны в Vesp.
Можешь прописать свои - https://stylelint.io
Спасибо большое!
Василий, добрый день!
Укажи, пожалуйста, где это сделать?
Я только один файл .stylelintcache в корне нашел, а в модуле @vesp ничего не нашел.
Всё верно, этот файл тебе и нужно менять.
Василий, добрый день!
Может быть ты имел дело с PWA в Nuxt 3, не подскажешь какой модуль лучше выбрать:
Есть официальный модуль: vite-pwa-nuxt, есть как будто второй официальный модуль @nuxtjs/pwa?
Похоже с вопросом поспешил, судя по обновлениям на Гитхабе @nuxtjs/pwa для Nuxt 2.
С PWA пока не разбирался, мне кажется это не особо популярная штука.
Если надо просто иконки добавить, то вот приятный сервис - https://realfavicongenerator.net
А сюда public/favicons с помощью этого сервиса иконки сгенерированы?
Честно говоря, не помню как именно было на этом сайте, он уже давно работает.
А так этот сервис у меня в закладках и я его регулярно использую.
Я подписан на PWA — русскоязычное сообщество в Телеграмме, правда не сильно успеваю читать все что там пишут, но по ощущениям есть надежда, что PWA потеснит нативные приложения. Даже iphone 14 стал принимать push-уведомления и разрешил ставить на iphone приложения из других store, хотя Apple долго держался так как хорошо зарабатывал на размещении приложений в Apple Store и ему было не выгодно развитие PWA.
Василий, подскажи, пожалуйста:
Есть сборка Nuxt3 + @vite-pwa/nuxt https://github.com/jahidanowar/nuxt3-pwa, делаю все так же на VESP 3 но никак не могу добиться, что бы сгенерировался манифест, перепробовал кучу вариантов.
Вопрос: в nuxt.config.ts мы пишем:
И этого достаточно, что бы в теории заработало?
По идее - да. Во всяком случае, именно так модули устанавливаются в Nuxt.
Ок, спасибо!
Нашел проблему, закомментировал в nuxt.config.ts строку:
Теперь манифест создается.
Вот список крупных сайтов с PWA https://github.com/FluorescentHallucinogen/pwa-awesome-ru?tab=readme-ov-file#%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B-pwa у Тинькова очень хорошо сделан, из-за реактивных технологий не поймешь, что не нативное приложение.
Правильно ли я понял, что это только для тех, у кого есть Apple Laptop и 10+ лет опыта бэкенд разработки?
То, что я вижу тут комментариях, это как люди с виндой натурально "пляшут" с бубнами (у всех разные).
Василий, уточните пожалуйста, на modhost работать не будет, верно? Потому что:
Ну и так далее. Т.е. никакие нужные допы я не смог поставить. Вероятно, я что то не так делаю. Ладно. Спасибо. Короче, зачем я вообще это тут пишу.
Верно, там нет Docker.
Нужен свой сервер, но я бы советовал начать с разработки на локальной машине.
Василий, добрый день!
Не подскажешь, как подключить плагины bootstrap-vue-next?
В Vesp 2 мы подключали нужные плагины в nuxt.config.js, а в Vesp 3 не пойму где их подключать, например тот же navbar в Орбите не нашел как он подключен.
А здесь ничего не надо вручную подключать, всё само автоматически импортируется.
Просто используй любые нужные компоненты BootstrapVue в коде и будет работать.
Спасибо, понял!
Василий добрый день!
Скажи, пожалуйста, как формируется ключ vueuse-color-scheme?
Пересмотрел все твои правки https://github.com/bezumkin/orbita/commit/1bdc25082af220669d469d0f2204dfe29f859c78, когда ты добавил Орбите темную тему, так и не понял, как VueUse генерирует этот ключ.
И еще скажи, в сохранении выбранной темы участвует только localStorage, в Pinia не участвует?
Помню, что в Vesp 2 при сохранении корзины данные писались в localStorage и Vuex.
Орбита использует Bootstrap 5.3, а он поддерживает смену темы прямо из коробки.
useColorMode нужен только для переключаения атрибута
data-bs-theme
у тегаbody
:const {system, store} = useColorMode({attribute: 'data-bs-theme', selector: 'body'}) console.log(system) // это системное значение темы - тёмная или светлая store.value = 'dark' // а это переключение темы в браузере
Дальше уже работает Bootstrap, никакие ключи я не формирую.
Нет, я не знаю зачем это писать в общее хранилище, если вся работа идёт в одном месте и другим компонентам эти данные не нужны.
Василий, спасибо!!!
Дело в том, что я решил добавить на главную страницу сайта анимированную презентацию, и сделать ее отключение для тех, кто ее уже видел и ему она надоела.
Я считал что Vuex, Pinia нужны для vue router для сохранения данных при переходе между страницами без перезагрузки, а если страница перезагружается то данные берутся с localStorage. Сейчас смотрю на компонент переключения темы с светлой на темную и понимаю, что он не использует Pinia а использует только localStorage.
Вот сейчас не могу понять, а как правильно, нужно ли в моей задачи использовать Pinia и localStorage или только один localStorage?
Нашел мануал, как совместно использовать Pinia и localStorage https://runthatline.com/how-to-use-local-storage-pinia/.
Pinia, как и Vuex нужны для обмена данными между компонентами.
Хранилища - реактивные. Если вывод формы авторизации завязан на значение в хранилище, то он отреагирует сразу после изменения этого значения. Таким образом форму авторизации можно показывать при попытке оставить комментарий, или голосовании - то есть из любого места приложения.
А в случае с localStorage, никакой реакции не будет, потому что компонент должен сам как-то следить за обновлением значения. Поэтому localStorage годится только для хранения данных между обновлениями страницы.
Для VueRouter ни реактивные хранилища, ни localStorage не нужны. Для твой задачи достаточно одного localStorage, просто запоминать, что юзер скрыл анимацию.
Спасибо большое за такой развернутый ответ!!
У меня вопрос по оформлению страниц на фронте. Понятно, что это не вопрос VESP-а... На стороне бэкенда я создал некое подобие блоговой ленты, содержащей все посты и страницу отдельного поста. Т.е. API отдает страницы http://127.0.0.1:8080/api/admin/posts и http://127.0.0.1:8080/api/web/posts/post-1 . Как понимаю, это означает, что бэкенд работает и данные в JSON отдает. Вопрос только в том, как это вывести на фронте? Вообще область бэкенда стала более понятной. Не на уровне детального понимания, но свет в конце туннеля забрезжил.) Плюс php подучиваю. А вот с фронтом пока беда - в "Data fetching" на Nuxt 3 я пока не могу въехать. Смотрю код отдельных страниц на Орбите, но там более сложная модель данных.
Верно.
Если это Vesp 3, то примерно так:
<template> <div class="wrapper"> <div v-for="item in items" :key="item.id"> <pre>{{ item }}</pre> <b-link :to="{name: 'posts-alias', params: {alias: item.alias}}">{{ item.title }}</b-link> </div> </div> </template> <script setup> const url = 'web/posts' const items = ref([]) try { items.value = await useGet(url) } catch (e) {} </script>
Это для вывода списка заметок со ссылкой на страницу каждой заметки.
Страница отдельного поста заработала сразу в том виде, как ты написал.) А вот в ленте постов контент не выводился - выдавалось
. Я пытался по-разному варьировать код и когда в ссылке вместо 'posts-alias' написал просто 'posts' ( т.е. -
) - получил на фронте контент, но в виде массива, как в бэкенде.)
Посты у меня состоят из title, content и уникального алиаса. На фронте я создал страницу
frontend/src/pages/posts/[alias].vue
для вывода отдельного поста. Может ты сможешь подсказать как самым простым методом вывести пусть хоть один title, чтобы дальше можно было это изучать и развивать?А страница с заметкой должна выглядеть как-то так:
<template> <div> <h1>{{ item.title }}</h1> <pre>{{ item }}</pre> </div> </template> <script setup> const url = 'web/posts/' + useRoute().params.alias const item = ref({}) try { item.value = await useGet(url) } catch (e) { showError({statusCode: e.statusCode || 500, statusMessage: e.statusMessage || 'Server Error'}) } </script>
Код пишу по памяти, не проверял - но примерно так всё и работает.
Огромное тебе спасибо!))
Василий, добрый день!
Не подскажешь, если установлено несколько копий VESP, то не будет ли проблем если они будут использовать одними и теме же контейнерами?
И еще, после обновления Докера возникла проблема, когда вторая копия VESP начала переименовывать контейнер добавляя в его имя ID:
А потом, при запуске, схлопывается после ошибки:
В итоге, сейчас могу пользоваться только первой копией VESPа, которая создала контейнеры, а все последующие установки VESPа, которые обращаются к этим контейнерам не запускаются из-за ошибки о которой написал выше.
Обрати внимание на настройку
COMPOSE_PROJECT_NAME
в файле.env
.Она должна быть уникальна для каждого проекта.
Блин, спасибо!
Совсем забыл, что в файле .env настройки хранятся, я дальше nuxt.config.ts не смотрю. Сори.
Василий, ты пишешь про trait FileModel. В дефолтной установке VESP3, которую мы ставим
его нет. Он есть только в репозитории vesp-core. Мне нужно как-то обновить ядро VESP, чтобы получить эти файлы? И еще вопрос - мне теперь нужно разобраться с добавлением изображений к постам. В предыдущем курсе (на Vesp/Nuxt2) загрузка изображений реализовывалась проще, как понимаю теперь для работы с новым Nuxt лучше освоить трейты?
Дефолтная установка Vesp тащит с собой и
vesp/core
, без него она просто не работает.Загрузка файлов реализуется так же, просто наследуешь свою модель от
Vesp\Models\File
, а она уже использует нужный трейт.Трейты к Nuxt не имеют никакого отношения, они для PHP.
Я имел в виду, что в репозитории Vesp, который мы скачиваем, в отличии от репозитория vesp-core, в директории
core/src/Models
нет директории Traits с файлом FileModel.php. И дефолтный файл core/src/Models/File.php у нас выглядит совсем не так. Там нет ссылок на трейты.Блин, туплю. Я смотрю на файлы своего проекта и не вижу там этих трейтов. Очевидно речь идет о файлах в докеровском контейнере php-fpm-1. Там есть файл
/vesp/core/vendor/vesp/core/src/Models/Traits/FileModel.php
. И значит мне в своем проекте директория src/Models/Traits с ее содержимым уже не нужна?Я ж не знаю, зачем ты её создавал. Если там нет ничего нужного - то, выходит, что не нужна.
Я просто немного запутался. Когда в абзаце "Vesp/Core" ты пишешь про "новый trait FileModel", я подумал, что это все должно быть в директории core моего проекта, также как, например, в Орбите есть директория core/src/Models/Traits. И когда ты посоветовал просто "наследовать модель от Vesp\Models\File" и она уже может использовать все методы твоего трейта - я просто не понял откуда все это возьмется, если в директории core у меня ничего такого нет. Я упустил из виду, что vesp-core под капотом Докера и можно так просто наследовать. Ну и Namespaces я еще не успел изучить, чтобы сразу понять твою мысль про
Vesp\Models\File
. Спасибо за разъяснение!