Пишем продвинутый планировщик с использованием React, Nest и NX. Часть 1: настройка проекта
Друзья, всем привет! Меня зовут Игорь Карелин, я frontend-разработчик в компании Домклик. В серии статей мы поэтапно разработаем продвинутое приложение-планировщик. Сначала создадим и настроим монорепозиторий c помощью NX, разработаем интерфейс с помощью React, добавим backend на основе NestJS, и, наконец, подключим базу данных MongoDB.
Будем использовать такие технологии:
NodeJS — программная платформа на движке V8 (компилирующем JavaScript в машинный код), которая превращает JavaScript из узкоспециализированного языка в язык общего назначения.
NX — система инструментов, позволяющая создавать монорепозитории для JavaScript-приложений.
TypeScript — язык программирования для разработки современных веб-приложений, расширяющий возможности традиционного JavaScript.
React — одна из самых популярных JavaScript-библиотек для создания пользовательских интерфейсов.
NestJS — фреймворк, который ускоряет и упрощает разработку масштабируемых серверных приложений на основе программной платформы NodeJS.
MongoDB — документоориентированная система управления базами данных, не требующая описания схемы таблиц. Считается одним из классических примеров NoSQL-систем, использует JSON-подобные документы и схему базы данных.
Docker — контейнеризатор приложений: программное обеспечение для автоматизации развёртывания и управления приложениями в средах с поддержкой контейнеризации.
Сначала установим NodeJs с официального сайта и редактор кода, я буду использовать Visual Studio Code.
Почему монорепозиторий?
Что такое монорепозиторий и для чего он нужен? Монорепозиторий — это стратегия разработки, при которой код нескольких приложений находится в одном репозитории. Это даёт ряд преимуществ:
Упрощённое управление зависимостями, в монорепозитории сборку легко оптимизировать, поскольку все зависимые компоненты находятся в одной и той же кодовой базе.
Сотрудничество между командами
Я выбрал монорепозиторий, чтобы не усложнять настройку проекта и иметь возможность легко переиспользовать различные компоненты, интерфейсы и типы. Создадим его с помощью NX — эта технология обеспечивает готовую структуру проекта и продвинутую работу с CLI для лёгкого создания и внедрения приложений. Ознакомиться с NX и узнать о нём подробнее вы можете по этой ссылке.
Создание и настройка проекта
Для создания проекта нам потребуется терминал, я работаю со штатным инструментом MacOS; в зависимости от операционной системы команды могут отличаться. Установите проект NX, в котором сразу будет присутствовать React, далее выберите директорию и выполните команду npx create-nx-workspace@latest --preset=react
.
В ходе установки нужно ответить на несколько пунктов:
Выберите любые названия проекта, приложений и препроцессор.
Название проекта: todo-app.
Название React-приложения: frontend.
Я выбрал SASS (.scss)
Готово! Мы только что создали проект NX с приложением React. Теперь установим NestJS. Сначала добавьте плагин Nest в существующую рабочую область. Перейдите в папку проекта и выполните команду npm install -D @nrwl/nest
.
Теперь создадим приложение Nest с помощью команды nx g @nrwl/nest:app backend --frontendProject frontend
. Мы сгенерировали приложение с названием «backend» и сообщили, что хотим связать его с «frontend». Благодаря NX нам не нужно вручную настраивать порты, всё будет сделано автоматически.
В файле proxy.conf.json NX сам добавил пути для работы с API. Теперь для получения данных из backend достаточно просто перейти на /api
:
proxy.conf.json
{
"/api": {
"target": "http://localhost:3333",
"secure": false
}
}
Давайте коротко обсудим некоторые папки, которые сгенерировал для нас NX:
/apps
— папка, в которой хранятся наши сгенерированые приложения frontend и backend;/libs
— здесь будут храниться части приложения, которые мы можем переиспользовать внутри монорепозитория (ведь одно из преимуществ — это упрощённое управление зависимостями и переиспользование кода между приложениями);/tools
— эта папка используется для различных правил или настроек. Например, правил EsLint, работы с автоматизацией и т.д.
Поговорив о создании и структуре проекта, самое время запустить его! И снова идём в терминал: nx run-many --parallel --target=serve --projects=backend,frontend
. Мы запустили параллельно несколько проектов без дополнительных настроек. Откройте браузер и проверьте, для этого перейдите по адресу localhost:4200
:
и по адресу localhost:4200/api
:
Отлично, всё работает!
Установка и подключение к базе данных
Сначала хочу предупредить вас: не стоит хранить в репозиториях файлы *.env и Docker-файлы с секретами! В статье я так делаю для ознакомительных целей.
Мы будем использовать MongoDB, её я выбрал исходя из простоты использования. Подробнее ознакомиться с этой базой данных вы можете на официальном сайте.
Использовать MongoDB можно несколькими способами:
Создать удалённую БД на серверах Mongo.
Установить MongoDB на свой компьютер.
Использовать Docker — этот способ мы и рассмотрим.
Для начала установите Docker на свой компьютер, инструкцию можете посмотреть на официальном сайте. После этого создайте в корне проекта файл docker-compose.yml с такой структурой:
version: '3'
services:
mongo:
image: mongo
container_name: mongo
restart: always
environment:
- MONGO_INITDB_ROOT_USERNAME=admin
- MONGO_INITDB_ROOT_PASSWORD=admin
ports:
- 27017:27017
volumes:
- ./mongo-data:/data/db
Подробно не буду останавливаться, про Docker написано множество статей и есть подробная официальная документация. Теперь запустите Docker Compose командой docker-compose up -d
. Docker скачает необходимые файлы для правильной работы и в корне проекта появится папка mongo-data
, в которой хранятся данные MongoDB, я добавил её в gitignore.
Следующим шагом нужно подключиться к БД из NestJS. Сначала установите необходимые зависимости: библиотеку mongoose для работы с БД и Nest config, который обеспечит работу с файлами *.env: npm install --save mongoose @nestjs/mongoose @nestjs/config
.
Я создал папку envs
и добавил файл .backend.env
, в котором объявил переменные:
DB_LOGIN=admin
DB_PASSWORD=admin
DB_HOST=localhost
DB_PORT=27017
DB_AUTHDATABASE=admin
Теперь создайте конфигурационный файл, который поможет генерировать ссылку для подключения к БД:
db-connect.config.ts
import { ConfigService } from '@nestjs/config';
import { MongooseModuleOptions } from '@nestjs/mongoose';
const getMongoString = (configService: ConfigService) =>
'mongodb://' +
configService.get('DB_LOGIN') +
':' +
configService.get('DB_PASSWORD') +
'@' +
configService.get('DB_HOST') +
':' +
configService.get('DB_PORT') +
'/' +
configService.get('DB_AUTHDATABASE');
const getMongoOptions = () => ({
useNewUrlParser: true,
useUnifiedTopology: true,
});
export const getMongoConfig = async (
configService: ConfigService
): Promise => {
console.log(getMongoString(configService));
return {
uri: getMongoString(configService),
...getMongoOptions(),
};
};
Далее перейдите в app.module.ts и импортируйте в него ConfigModule и MongooseModule. Пара слов о модулях в NestJS: это классы с декоратором Module()
, предоставляющим метаданные, которые Nest использует для организации структуры приложения.
В конечном счёте файл будет выглядеть так:
app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { MongooseModule } from '@nestjs/mongoose';
import { getMongoConfig } from '../config/db-connect.config';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true, // Позволяет обратиться к env во всем приложении
envFilePath: 'envs/.backend.env', // Указываем путь до env файла
}),
MongooseModule.forRootAsync({ // Модуль для работы с mongo
imports: [ConfigModule],
inject: [ConfigService],
useFactory: getMongoConfig, // добавляем созданную ранее функцию подключения к БД
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
На этом пока остановимся. Мы разобрали настройку проекта и подключение к базе данных для дальнейшей работы. В следующих частях напишем логику работы с базой данных, добавим регистрацию пользователей и т.д. Спасибо за внимание!
Исходный код доступен по ссылке.