Вопрос: а зачем было пытаться установить мускул локально, если я в статье писал как запускать мускул в рамках докер-проекта?
Доброго времени суток!

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

1. Установил
sudo apt-get update sudo apt-get upgrade
sudo apt-get install mysql-server

2. Поменял аутоиндентификацию доступ для root с auth_socket на mysql_native_password

Перестал пускать :
sudo mysql -u -p root
Error 1045 (28000) access denied for user 'root'@'localhost

>> То есть завести прям отдельную таблицу, в которой связаны по id пост и гриб? Тогда enum вообще лишний?

Таки да.
>> Вопрос: что не так со списками и как правильно связать с "создателем" (
createdById String? @db.VarChar(32) CreatedBy User? @relation(fields: [createdById], references: [id])
) ?

Смотри модель пользователя текущего сайта, наверняка поймешь.
Спасибо!
>>Но сущность типа Гриб лучше было бы сразу загнать в таблицу.

То есть завести прям отдельную таблицу, в которой связаны по id пост и гриб? Тогда enum вообще лишний?
>> Нашел про списки:
Правильно t.field('mashroom, { type: Mashrooms })

В целом да, правильно, но есть НО: ты прописал type: Mashrooms и здесь у тебя Mashrooms - это не строковое название типа, а именно сам объект, то есть
export const Mashrooms = enumType({ name: 'Mashrooms', members: ['Noinfo', 'Mash1', 'Mash2'], description: 'Список грибов', })
Правильней указать строковое имя, то есть { type: "Mashrooms" }

Вторая подсказка: категорически избегай названий типов с окончанием на s (то есть множественность). В каком-то месте тебе надо будет массив таких типов и как ты будешь писать? Mashroomss? Особенно не советую наименование типов (именно тех, которые идут потом в названия таблиц, а не колонки) на s заканчивать в самой призма-схеме. Призма втупляет с формированием имен множественных переменных и получается все очень плохо.

Подсказка 3: имена типов в графе уникальные. Если ты назвал енам Mashroom, то имей ввиду, что потом если захочешь создать тип Mashroom (чтобы у него была своя таблица), не получится. Нельзя и тип и енам иметь с одним названием. Обычно енамы для каких-то совсем не больших списков используют (к примеру, статусов). Но сущность типа Гриб лучше было бы сразу загнать в таблицу.

Нашел про списки:
Правильно t.field('mashroom, { type: Mashrooms })
Николай, привет!
Ковыряю nexus, нужна помощь.

Я добавил в схему призмы таблицу:

model Post { id String @id @default(cuid()) @db.VarChar(32) createdAt DateTime @default(now("0")) @db.DateTime(0) updatedAt DateTime @default(now("0")) @updatedAt @db.DateTime(0) mashroom Mashrooms @default(value: Noinfo) text String createdById String? @db.VarChar(32) CreatedBy User? @relation(fields: [createdById], references: [id]) @@index([createdById], name: "User") } enum Mashrooms { Noinfo Mash1 Mash2 }
Пишу проверку типов в нексусе для поста:


import { objectType, enumType} from 'nexus' export const Post = objectType({ name: 'Post', description: 'Пост', sourceType: { module: '@prisma/client', export: 'Post', }, definition(t) { t.nonNull.string('id') t.nonNull.date('createdAt', { description: 'Когда создан', }) t.nonNull.date('updatedAt', { description: 'Когда обновлен', }) t<typeof Mashrooms>('mashroom', { description: 'Гриб', }) t.string('text') }, }) export const Mashrooms = enumType({ name: 'Mashrooms', members: ['Noinfo', 'Mash1', 'Mash2'], description: 'Список грибов', })

Вопрос: что не так со списками и как правильно связать с "создателем" (
createdById String? @db.VarChar(32) CreatedBy User? @relation(fields: [createdById], references: [id])
) ?
Всем привет!

Сегодня напишу обновленную инструкцию по быстрому запуску тестового проекта локально. Он вполне подойдет для экспериментов как с фронтом, так и с бэком.


Что вы получите

Локально работающие в докер-контейнерах:
  1. Сервер системы управления базами данных MySQL.
  2. PhpMyAdmin для быстрого доступа к базам данных.
  3. Почтовый сервер MailHog для тестирования отправки емейл-сообщений с сервера.
  4. Caddy - прокси-сервер для обработки запросов.
Какое программное обеспечение у вас должно стоять

  1. Желательно, чтобы у вас в качестве операционной системы использовалась ubuntu или типа того. Просто тогда я могу помочь с установкой необходимого программного обеспечения (где-то уже на страницах самих технологий я прописал способ установки). К тому же я буду писать код, который надо будет выполнять в терминале. Не могу гарантировать, что на вашей системе это так же будет работать. Но если у вас используется другая операционная система, то от вас просто потребуется самостоятельная установка и настройка требуемого ПО и, возможно, терминальные команды адаптировать под себя. В остальном же все должно работать и на вашей системе.
  2. git - контроль версий файлов. Понадобится, чтобы стягивать с github нужные нам проекты.
  3. node-js - серверная среда исполнения Javascript
  4. yarn - менеджер пакетов.
  5. docker - сервер управления виртуальными машинами (контейнерами)
  6. docker-compose - оркестрация докер-контейнеров в рамках отдельных проектов
  7. VSCode - IDE - Среда разработки, то есть где мы будем писать код.

Создание и запуск тестового проекта

Для начала нам надо скачать докер-проект, в рамках которого мы и запустим нужные нам сервера (MySQL и т.п.)

Здесь и далее все команды выполняются в терминале.

1. Создадим папку для всех проектов
mkdir ~/www -p
Команда mkdir создает указанную директорию, а параметр -p дает сразу два плюса: 1. не возникает ошибки, если директория уже существует. 2. Позволяет указать в пути сразу несколько вложенных директорий и все они будут созданы, если отсутствуют.

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

2. Переходим в нашу папку
cd ~/www

3. Клонируем с гитхаба докер-проект.
git clone https://github.com/prisma-cms/docker-nextjs.git docker-nextjs-test --recurse-submodules
git - это программа, а clone - это подпрограмма программы git.
https://github.com/prisma-cms/docker-nextjs.git docker-nextjs-test - параметры (или по-другому опции).
--recurse-submodules - атрибут

Просто сразу учитесь распознавать что есть что в вызываемых командах. Синтаксис примерно одинаковый везде.

Здесь я указал адрес клонируемого проекта и папку, в которую поместить его содержимое (в моем случае это docker-nextjs-test). Можно и не указывать папку, тогда она будет создана исходя из названия проекта (в данном случае это было бы docker-nextjs).

Проект клонируется в ту папку, в которой вы находитесь.

Перейдем в папку проекта
cd docker-nextjs-test
cd - команда смены текущей директории (change directory)
В нашем случае указана директория docker-nextjs-test. Следует отметить, что это относительный путь, то есть путь будет формироваться относительно текущей директории. Если у нас в текущей директории (где мы сейчас находимся) есть папка docker-nextjs-test, то переход в нее будет выполнен успешно. Если нет такой папки, то будет ошибка. Еще существует понятие абсолютный путь. Это когда указывается полный путь. В линуксе корнем файловой системы является / (слеш). Когда мы создавали свою папку рабочую, мы указывали путь ~/www. Этот путь тоже следует называть абсолютным, потому что символ ~ (тильда) указывает на нашу корневую директорию, то есть имеет явное значение.

Обратите внимание на флаг --recurse-submodules. Он нужен для того, чтобы вместе с основным гит-проектом стянуть и указанные в нем модули. Выполните вот этот код:
ls -la nextjs-nexus/
Команда ls выводит список файлов и папок в указанной директории (если не указана, то в текущей). Параметр -l указывает, что надо вывести все списком в столбик, а параметр -a указывает, что надо вывести все файлы, даже скрытые (в линуксе все файлы, имена которых начинаются с точки, считаются скрытыми).

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

Вернемся в корневую директорию нашего докер-проекта, поднявшись на директорю выше, выполнив cd .. (двоеточие - это родительская директория. Одна точка - это текущая директория).

Теперь откроем наш проект в IDE VSCode. Проще всего сделать это выполнив прям в текущей директории команду
code .
Обратите внимание на символ точки после команды code - это не просто так точка, а указание на текущую директорию. Если вы просто выполните команду code без точки, то просто будет открыт редактор без текущего проекта (или последний используемый проект, если уже работали раньше). Нам же надо не просто запустить редактор, а чтобы сразу и проект был открыт. Должно быть типа такого:


Здесь мы в левой навигационной панели сразу видим файлы нашего проекта.

Для начала откройте файл readme.md, щелкнув по нему дважды мышкой.

Подсказка: если щелкнуть мышкой один раз, то открывшийся файл не будет закреплен во вкладке. В таком случае, если вы кликните другой файл, то будет открыт новый, а текущий файл закрыт.

Открыв файл readme.md, вы увидите не самый читаемый текст.


Дело в том, что это текст в формате markdown и здесь мы видим исходный код, а не его форматированное представление. Это все равно как смотреть страницы сайта не в браузере, а их исходный HTML-код. Дя того, чтобы увидеть в преобразованном виде, надо включить просмотрщик. Обратите внимание на иконки в правом верхнем углу. Там есть иконки с лупой (у меня их две, но у вас скорее всего будет одна, у меня просто какой-то еще vscode-плагин добавляет). Кликните его и увидите нормально читаемый текст.


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

Копируем и редактируем .env

Итак, прежде чем перейти непосредственно к запуску докер-контейнеров, надо нам сначала создать и отредактировать файл .env
Это файл переменных окружения (читайте - конфигурационный файл). Для удобства в корне проекта уже есть файл .env.sample, поэтому мы просто скопируем его. Для этого выполним команду
cp .env.sample .env
Команда cp копирует файл[ы]. В нашем случае исходный файл .env.sample будет скопирован в .env

Теперь откроем этот файл в IDE. Сейчас его содержимое такое:

NETWORK_NAME=prisma-cms-default # MySQL root password MYSQL_PASSWORD=prisma # Database access link for nextjs-nexus # user:password@host:port/database_name NEXTJS_DATABASE_URL=mysql://root:prisma@mysql:3306/nextjs-nexus # Required for yarn prisma:seed # Create sudo use with username "admin" and this password NEXTJS_SUDO_PASSWORD= # API_ENDPOINT=http://api:4000 APP_SECRET=YOUR_STRONG_SECRET

Сейчас, так как у нас просто тестовый проект, да еще и локально, можно все оставить как есть, задав только свой пароль в переменную NEXTJS_SUDO_PASSWORD, например demo, то есть получится NEXTJS_SUDO_PASSWORD=demo
Нам этот пароль понадобится чуть позже, когда мы будем выполнять посев данных (я позже это покажу/расскажу).


Запуск докер-контейнеров.

Когда наш конфиг готов, можно переходить непосредственно к запуску необходимых контейнеров. В рамках docker-compose они называются службами (service). Откройте файл docker-compose.yml
В нем в формате yaml прописана конфигурация нашего докер-проекта.


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

Как мы видим, здесь перечислено несколько служб (services), а именно:
  • mysql - сервер баз данных
  • pma - PhphMyAdmin
  • proxy - прокси-сервер
  • mail - почтовый сервер
  • nextjs-nexus - наш JS-проект, но его мы сейчас не будем в докере запускать.
и если дальше сам файл пролистать, там можно еще найти rtcmultyconnection и coturn, но они нам сейчас не нужны и мы их не будем запускать.

Запуск сервера MySQL

Важно: Для того, чтобы не вводить sudo каждый раз при запуске docker, добавьте имя своего пользователя в группу docker:
sudo usermod -aG docker $(whoami) (добавляет именно текущего пользователя, поэтому убедитесь, что вы авторизованы нужным пользователем).
Для добавления произвольного пользователя sudo usermod -aG docker USERNAME

Первым делом мы запустим сервер баз данных MySQL. Для этого выполним команду:
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d --build mysql
Что здесь происходит?

docker-compose - это сама программа.

Флаг -f - это указывает какой файл конфигурации использовать (за этим флагом идет имя файла). В нашем случая указывается два файла (и два раза используется -f)
-f docker-compose.yml -f docker-compose.dev.yml
Если вы посмотрите содержимое директории, то увидите, что там действительно помимо файла docker-compose.yml имеется еще и docker-compose.dev.yml. А плюс к этому еще и docker-compose.prod.yml, но сейчас он нам не нужен, он для запуска контейнеров в боевом режиме и сейчас мы не будем его рассматривать. Дев-конфиг нужен для того, чтобы переопределить некоторые базовые конфиги. Сейчас разбирать их не будем, но кому интересно, посмотрите сами и попробуйте разобраться. Отмечу только, что в основном это открытие портов и подключение отдельных разделов файловой системы.

up - это подпрограмма программы docker-compose. Запускает указанную службу/службы (или все службы, если не указано какие именно). В нашем случае служба mysql (смотрим ее в конфиге).

Между подпрограммой up и именем службы mysql есть еще два флага: -d и --build. Здесь важно понимать, что эти флаги относятся не к самой программе docker-compose, а именно к подпрограмме up, и поэтому именно такой порядок (и обязательно перед названием службы, а не после).

Флаг -d - указывает, что процесс надо запустить в режиме демона, то есть после успешного запуска контейнера программа docker-compose завершает свое выполнение и терминал можно будет закрыть, а контейнер продолжит работать. В противном случае docker-compose будет работать, пока не будет отправлен сигнал выхота (Нажатие клавишь Ctrl+C). Тогда программа остановится и контейнер тоже.

Флаг --build указывает на то, что контейнер надо предварительно собрать. Пока не будем вдаваться в подробности, просто знайте это. Конкретные сценарии сборки зависят от конкретных служб.

При первом выполнении весь процесс займет какое-то время, потому что у вас локально нет еще нужных образов для устанавливаемых контейнеров, поэтому они сначала будут загружены и только потом собраны и установлены. После установки можно проверить наличие работающих контейнеров. Выполним
docker-compose ps
Подпрограмма ps выводит список работающих служб. У меня сейчас так:


То есть работает один контейнер с именем docker-nextjs-test_mysql_1.
Обратите внимание на State up - это текущий статус контейнера и он говорит о том, что он сейчас работает. Могут быть и другие статусы типа Exit и Restarting, но тогда это будет не хорошо (Первый говорит, что контейнер завершил работу и ОК, если с кодом 0, то есть Exit 0. Код 1 будет говорить о внутренней ошибке, другие коды по ситуации. А второй говорит о том, что что-то пошло не так, контейнер развалился, но он пытается опять запуститься). Так или иначе, в нашем случае не up будет не хорошо. А если up, то хорошо :)

0.0.0.0:3306->3306/tcp говорит о том, что локальный порт 3306 вашего компьютера открыт и проксируем запросы на порт 3306 этого контейнера. Про порты погуглите немного, информация полезная, но сейчас не будем на ней заострять внимание. Отмечу только, что если у вас локально уже запущен MySQL-сервер и он уже занял этот порт, то вы получите ошибку и контейнер не будет запущен (порт уже занят). В таком случае или остановите свой сервер или не запускайте этот, вы можете и свой использовать (надо только путь в конфиге .env поменять). Или можете в конфиге композа поменять открытый порт для службы mysql и иметь два локально запущенных сервера на разных портах (опять-таки придется подправить и путь в .env).

Итак, если все ОК, значит MySQL мы запустили и пришло время заглянуть в него. Для этого нам понадобится PhpMyAdmin. Запустим его по той же схеме (только имя службы укажем корректное)
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d --build pma

После того, как выполнится, опять-таки проверим список процессов


Мы видим, что у нас теперь работает еще и docker-nextjs-test_pma_1 и для него открыт порт 8090. Вот теперь мы что-то можем уже посмотреть. Для этого откроем в браузере страницу http://localhost:8090. Должен работать интерфейс PhpMyAdmin

Внимание! У нас здесь используется http, а браузер Mozilla с недавних пор стал блокировать отправку форм по http, так что в нем авторизоваться скорее всего не получится. Но в любом случае, советую использовать браузер google chrome, потому что на мой взгляд там более удобный и прокаченный dev tools.


Теперь вопрос: какой логин/пароль? Логин root, а пароль тот, что был указан в .env, а именно MYSQL_PASSWORD=prisma, то есть суммарно root/prisma
Авторизуемся и посмотрим что там у нас есть.


Сейчас у нас там только технические базы данных, то есть по сути ничего пользовательского нет. Так что теперь наш следующий шаг - запустить JS проект и создать для него базу данных. А пока что про docker-compose забудим, пусть работает, мы сделали все необходимое.

Запуск JS проекта

Помните, когда мы клонировали наш гит-проект, мы указывали флаг --recurse-submodules? Это мы делали, чтобы скачались и дочерние гит-модули. Откройте файл .gitmodules

Сейчас в нем прописано так:
[submodule "nextjs-nexus"] path = nextjs-nexus url = https://github.com/prisma-cms/nextjs-nexus branch = master
Давайте разбираться.
  • [submodule "nextjs-nexus"] - Начало конфига модуля и его имя - nextjs-nexus
  • path = nextjs-nexus - Это в какой папке хранится содержимое этого модуля. Путь относительный от корня гит-проекта.
  • url = https://github.com/prisma-cms/nextjs-nexus - адрес источника модуля (remote)
  • branch = master - текущий бранч.
То есть, чтобы нам перейти в папку модуля из текущей директории проекта, достаточно выполнить cd nextjs-nexus.
Прежде чем что-то делать дальше, давайте сразу здесь выполним команду git status (что-бы посмотреть статус текущего гит-проекта).

Обратите внимание, что когда мы находимся внутри конкретного модуля, git смотрит не корневой гит-проект, а именно текущий модуль.

Сейчас у меня так.


Дело в том, что модуль был склонирован в рамках родительского гит-проекта и тот управляет состоянием модуля. В общем, это дебри, но нам надо переключиться в мастер, чтобы меньше заморочек было. Выполним
git checkout master
Результат
Previous HEAD position was 12f097f Sendmail Switched to branch 'master' Your branch is up to date with 'origin/master'.
Все, мы на основной ветке. Это нам нужно для того, чтобы мы в дальнейшем могли спокойно подтягивать с гитхаба свежие изменения по самому модулю. При этом, если подняться в родительский проект и выполнить git status, то мы увидим такое:


Дело в том, что корневой гит-проект запоминает коммиты модулей, и когда стягивает эти модули, тянет именно сохраненные коммиты (то, что и было в HEAD). Но позже я в дочерний проект новые коммиты слал, а в корневом проекте они не были зафиксированы. А сейчас, переключив ветку в дочернем модуле, мы там переключились на самый последний коммит. Главный модуль увидел эти новые коммиты и говорит "О, новые коммиты! Их можно закоммитить в рамках корневого проекта". Но я это сообщаю просто на заметку, сейчас же для нас это роли особой не играет, так что оставим как есть.

Запустим IDE в JS - проекте

До этого мы запускали VSCode в корневом проекте. Но сейчас мы будем работать с конечным JS-проектом, поэтому откроем новое окно IDE именно в этой директории. Для этого опять выполним code . (с точкой на конце). Старое окно VSCode можем закрыть.

Опять-таки, здесь есть свой .env.sample. Скопируем его в .env


Здесь нам надо только указать свой пароль в переменную SUDO_PASSWORD, например SUDO_PASSWORD=admin. В остальном же, если вы ничего лишнего не меняли в .env докер-проекта, сейчас здесь ничего больше править не надо.

Установим зависимости

В гит у нас хранятся только исходные файлы самого проекта. Но для работы нам надо много сопутствующих пакетов (все они прописаны в package.json). Чтобы установить их, выполним команду
yarn
На самом здесь выполняется yarn install, но yarn тоже работает, то есть без указания подпрограммы по умолчанию выполняется install

Сейчас будет много всего скачиваться, особенно в первый раз, и если у вас интернет слабый, придется подождать (можно сходить кофе попить). А все это добро будет записано в папку node_modules.

На выходе должно быть что-то типа
[4/4] Building fresh packages...
Done in 77.44s.

Когда все пакеты установлены, можно переходить к следующему шагу.

Деплой базы данных

Как вы помните, у нас еще нет своей базы данных в MySQL. Нам ее надо создать. Но это совсем не сложно сделать. Откройте панель NPM SCRIPTS и выполните yarn prisma:deploy

Результат выполнения:


Если у вас нет панельки NPM SCRIPTS, то кликните правой кнопкой мышки другую панельку и в выпадашке поставьте галочку.

Заметка 2: сами скрипты прописаны в package.json в секции "scripts" и все их можно выполнить и в терминале, к примеру, yarn prisma:deploy

Как видно, было найдено 7 миграций (они находятся в папке prisma/migrations) и все они были успешно выполны.

Вот теперь вернемся в PhpMyAdmin, обновим страницу и увидим, что у нас появилась база данных nextjs-nexus


Пока что все таблицы за исключением технической таблицы _prisma_migrations пустые, то есть у нас была создана только структура, но никакие сырые данные мы туда не создавали. Но уже сейчас можно запустить наш проект, чтобы посмотреть результат в браузере. Для этого в терминале выполним
yarn dev
Если все ОК, вы увидите в терминале > Ready on http://localhost:3000
То есть наш веб-сервер запустился на порту 3000. Откроем страницу http://localhost:3000

Сейчас мы увидим совсем мало, ведь это почти чистая заготовка.


Вспоминается мем))


Тем не менее, нам нужен как минимум стартовый пользователь (админ). И у нас есть скрипт на его создание. Выполним там же в npm-скриптах скрипт prisma:seed
Результат выполнения:

Теперь, если зайти в таблицу User, можно найти запись админа


И теперь можно авторизоваться с этим пользователем. Заходим на страницу http://localhost:3000/signin и пробуем авторизоваться admin/admin (у вас пароль будет другой, если вы указали другой). У меня авторизация прошла успешно.


Так же можно проверить работу формы регистрации http://localhost:3000/signup

Если вы уже авторизованы, то удалите токен авторизации. Для этого откройте консоль браузера (Ctrl+Shift+i или F12) и выполните delete localStorage.token и обновите страницу (сорри, забыл сделать кнопочку разлогинивания).


Первые эксперименты

Ну а теперь первый маленький эксперимент: попробуем что-то изменить в исходном коде проекта, чтобы увидеть результат на странице браузера. Перейдем опять на главную страницу http://localhost:3000 (напомню, что там просто выводится надпись Main Page). Откроем в IDE файл src/pages/MainPage/index.tsx


Невооруженным глазом здесь можно найти <div>Main Page</div>. Вот здесь можно редактировать, сохранять и почти сразу увидеть результат на странице без перезагрузки страницы браузера (если у вас все еще выполняется yarn dev). Сразу отмечу, что это реакт-компонент и это именно функциональный компонент (то есть суть его - функция). Есть еще class-based components, то есть компоненты на основе классов. Необходимый минимум вы можете освоить пройдя уроки в этом разделе.

Так же отмечу, что эта статья неспроста написана такая подробная. Много дальнейших ответвлений в обучении будет именно поверх этой заготовки. Поэтому, если вы заинтересованы в практике, отработайте данный материал ответственно. Если все получится, всем используемым здесь технологиям в своем профиле проставьте по единичке, если еще не сделано. Это уже элементарный уровень и ваши первые шаги в развитии.

Если что-то не понятно или не получается, спрашивайте.