Сборка приложений на NestJS и Angular и запуск их в двух вариантах: через PM2 и через «Docker Compose»

от автора

Предыдущая статья: Добавление Swagger документации в NestJS-mod приложение и генерация REST-клиента для Angular-приложения

Для запуска собранных приложений в режиме PM2 фронтенд будет встроен в бэкенд в виде статичных файлов.

Для запуска в режиме «Docker Compose» бэкенд будет собран в виде Docker образа, а собранная статика фронтенда будет отдаваться через и Nginx.

База данных запускается через «Docker Compose».

1. Устанавливаем все необходимые пакеты и перегенерируем клиентов Prisma

После установки пакетов сгенерированные клиенты Prisma удаляются, поэтому нужно повторно прогонять генерацию.

Команды

# Install all need dependencies npm install --save @nestjs/serve-static dotenv wait-on  # After installing the packages, the generated Prisma clients are deleted, so you need to run their generation again npm i && npm run generate 
Вывод консоли
npm install --save @nestjs/serve-static dotenv wait-on  added 3 packages, and audited 2770 packages in 11s  331 packages are looking for funding   run `npm fund` for details  18 vulnerabilities (6 moderate, 12 high)  To address issues that do not require attention, run:   npm audit fix  To address all issues (including breaking changes), run:   npm audit fix --force  Run `npm audit` for details. 

2. Добавляем модуль для подключения статики в NestJS-приложение

Приложение NestJS-mod имеет специальную секцию для подключения такого вида модулей Core-модули, но на данном этапе для упрощения понимания такие глобальные вещи будут подключатся на уровне AppModule.

Обновленный файл apps/server/src/app/app.module.ts

import { createNestModule, NestModuleCategory } from '@nestjs-mod/common';  import { PrismaModule } from '@nestjs-mod/prisma'; import { ServeStaticModule } from '@nestjs/serve-static'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { join } from 'path';  export const { AppModule } = createNestModule({   moduleName: 'AppModule',   moduleCategory: NestModuleCategory.feature,   imports: [     PrismaModule.forFeature({ featureModuleName: 'app' }),     ServeStaticModule.forRoot({       rootPath: join(__dirname, 'assets', 'client'),     }),   ],   controllers: [AppController],   providers: [AppService], }); 

3. Добавляем новый конфигурационный файл PM2 для запуска собранного бэкенд и фронтенд приложения

Приложение будет только одно, так как статика фронтенд-приложения ложится рядом с собранным бэкенд-приложением.

Создаем файл ecosystem-prod.config.json

{   "apps": [     {       "name": "nestjs-mod-fullstack",       "script": "node dist/apps/server/main.js",       "node_args": "-r dotenv/config"     }   ] } 

4. Добавляем новые скрипты и обновляем существующие

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

Группы схожих по области применения скриптов объединены в некий заголовок _____group name_____.

Обновляем секцию с скриптами в файле package.json

{   "scripts": {     "_____pm2-full dev infra_____": "_____pm2-full dev infra_____",     "pm2-full:dev:start": "npm run generate && npm run docker-compose:start-prod:server && npm run db:create && npm run flyway:migrate && npm run pm2:dev:start",     "pm2-full:dev:stop": "npm run docker-compose:stop-prod:server && npm run pm2:dev:stop",     "_____dev infra_____": "_____dev infra_____",     "serve:dev": "./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=serve",     "serve:dev:server": "./node_modules/.bin/nx serve server --host=0.0.0.0",     "_____pm2 dev infra_____": "_____pm2 dev infra_____",     "pm2:dev:start": "./node_modules/.bin/pm2 start ./ecosystem.config.json && npm run wait-on -- --log http://localhost:3000/api/health --log http://localhost:4200",     "pm2:dev:stop": "./node_modules/.bin/pm2 delete all",     "_____pm2-full prod infra_____": "_____pm2-full prod infra_____",     "pm2-full:prod:start": "npm run generate && npm run build -- -c production && npm run copy-front-to-backend && npm run docker-compose:start-prod:server && npm run db:create && npm run flyway:migrate && npm run pm2:start",     "pm2-full:prod:stop": "npm run docker-compose:stop-prod:server && npm run pm2:stop",     "_____prod infra_____": "_____prod infra_____",     "start": "./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=start",     "build": "npm run generate && npm run tsc:lint && ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=build --skip-nx-cache=true",     "start:prod:server": "./node_modules/.bin/nx start server",     "_____pm2 prod infra_____": "_____pm2 prod infra_____",     "pm2:start": "./node_modules/.bin/pm2 start ./ecosystem-prod.config.json && npm run wait-on -- --log http://localhost:3000/api/health --log http://localhost:3000",     "pm2:stop": "./node_modules/.bin/pm2 delete all",     "_____docker-compose-full prod infra_____": "_____docker-compose-full prod infra_____",     "docker-compose-full:prod:start": "npm run generate && npm run build -- -c production && npm run docker:build:server:latest && export COMPOSE_INTERACTIVE_NO_CLI=1 && docker-compose -f ./.docker/docker-compose-full.yml --env-file ./.docker/docker-compose-full.env --compatibility up -d",     "docker-compose-full:prod:stop": "export COMPOSE_INTERACTIVE_NO_CLI=1 && docker-compose -f ./.docker/docker-compose-full.yml --env-file ./.docker/docker-compose-full.env --compatibility down",     "docker-compose-full:prod:only-start": "export COMPOSE_INTERACTIVE_NO_CLI=1 && docker-compose -f ./.docker/docker-compose-full.yml --env-file ./.docker/docker-compose-full.env --compatibility up -d",     "docker-compose-full:prod:test:e2e": "export BASE_URL=http://localhost:8080 && npm run test:e2e",     "_____docs_____": "_____docs_____",     "docs:infrastructure": "export NESTJS_MODE=infrastructure && ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source,client* --all -t=serve --parallel=1 -- --watch=false --inspect=false",     "_____docker-compose infra_____": "_____docker-compose infra_____",     "docker-compose:start:server": "export COMPOSE_INTERACTIVE_NO_CLI=1 && docker compose -f ./apps/server/docker-compose.yml --compatibility up -d",     "docker-compose:stop:server": "export COMPOSE_INTERACTIVE_NO_CLI=1 && docker compose -f ./apps/server/docker-compose.yml down",     "_____docker-compose prod-infra_____": "_____docker-compose prod-infra_____",     "docker-compose:start-prod:server": "export COMPOSE_INTERACTIVE_NO_CLI=1 && docker-compose -f ./apps/server/docker-compose-prod.yml --env-file ./apps/server/docker-compose-prod.env --compatibility up -d",     "docker-compose:stop-prod:server": "export COMPOSE_INTERACTIVE_NO_CLI=1 && docker-compose -f ./apps/server/docker-compose-prod.yml --env-file ./apps/server/docker-compose-prod.env down",     "_____docker_____": "_____docker_____",     "docker:build:server:latest": "docker build -t nestjs-mod-fullstack-server:latest -f ./.docker/server.Dockerfile . --progress=plain",     "_____tests_____": "_____tests_____",     "test": "./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=test --skip-nx-cache=true --passWithNoTests --output-style=stream-without-prefixes",     "test:e2e": "./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=e2e --skip-nx-cache=true --output-style=stream-without-prefixes",     "test:server": "./node_modules/.bin/nx test server --skip-nx-cache=true --passWithNoTests --output-style=stream-without-prefixes",     "_____lint_____": "_____lint_____",     "lint": "npm run tsc:lint && ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=lint",     "lint:fix": "npm run tsc:lint && ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=lint --fix",     "tsc:lint": "./node_modules/.bin/tsc --noEmit -p tsconfig.base.json",     "_____db_____": "_____db_____",     "db:create": "./node_modules/.bin/nx run-many -t=db-create",     "_____flyway_____": "_____flyway_____",     "flyway:create:server": "./node_modules/.bin/nx run server:flyway-create-migration",     "flyway:migrate:server": "./node_modules/.bin/nx run server:flyway-migrate",     "flyway:migrate": "./node_modules/.bin/nx run-many -t=flyway-migrate",     "_____prisma_____": "_____prisma_____",     "prisma:pull:server": "./node_modules/.bin/nx run server:prisma-pull",     "prisma:pull": "./node_modules/.bin/nx run-many -t=prisma-pull",     "prisma:generate": "./node_modules/.bin/nx run-many -t=prisma-generate",     "_____utils_____": "_____utils_____",     "copy-front-to-backend": "rm -rf dist/apps/server/assets/client && cp -r dist/apps/client/browser dist/apps/server/assets/client",     "generate": "./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=generate --skip-nx-cache=true && npm run make-ts-list && npm run lint:fix",     "tsc": "tsc",     "nx": "nx",     "dep-graph": "./node_modules/.bin/nx dep-graph",     "make-ts-list": "./node_modules/.bin/rucken make-ts-list",     "manual:prepare": "npm run generate && npm run docs:infrastructure && npm run test",     "update:nestjs-mod-versions": "npx -y npm-check-updates @nestjs-mod/* nestjs-mod -u",     "rucken": "rucken",     "wait-on": "./node_modules/.bin/wait-on --timeout=240000 --interval=1000 --window --verbose"   },   "scriptsComments": {     "pm2-full:dev:start": ["Запуск инфраструктуры и всех приложений в режиме watch через PM2"],     "pm2-full:dev:stop": ["Остановка инфраструктуры и всех приложений в режиме watch через PM2"],     "pm2:dev:start": ["Запуск всех приложений в режиме watch через PM2"],     "pm2:dev:stop": ["Остановка всех приложений в режиме watch через PM2"],     "pm2-full:prod:start": ["Запуск инфраструктуры и сборка всех приложений с последующим запуском их через PM2"],     "pm2-full:prod:stop": ["Остановка инфраструктуры и всех приложений запущенных через PM2"],     "test:e2e": ["Запуск E2E-тестов для всех пприложений"],     "copy-dist-front-to-dist-backend": ["Копирование собранного фронтенд приложения в собранный бэкенд"],     "wait-on": ["Утилита для проверки и ожидания доступности сайта"],     "docker-compose-full:prod:start": ["Билд и запуск Docker Compose инфраструктуры с бэкендом в виде Docker контейнера и статикой фронтенда отдающуюся через Nginx"],     "docker-compose-full:prod:stop": ["Остановка Docker Compose инфраструктуры и всех приложений"],     "docker-compose-full:prod:only-start": ["Запуск Docker Compose инфраструктуры с бэкендом в виде Docker контейнера и статикой фронтенда отдающуюся через Nginx"],     "docker-compose-full:prod:test:e2e": ["Запуск E2E-тестов на приложение запущенное через Docker Compose"],     "docker:build:server:latest": ["Сборка Docker образа бэкенда"]   } } 

Описания новых скриптов

Script

Comment

pm2-full:dev:start

Запуск инфраструктуры и всех приложений в режиме watch через PM2

pm2-full:dev:stop

Остановка инфраструктуры и всех приложений в режиме watch через PM2

pm2:dev:start

Запуск всех приложений в режиме watch через PM2

pm2:dev:stop

Остановка всех приложений в режиме watch через PM2

pm2-full:prod:start

Запуск инфраструктуры и сборка всех приложений с последующим запуском их через PM2

pm2-full:prod:stop

Остановка инфраструктуры и всех приложений запущенных через PM2

test:e2e

Запуск E2E-тестов для всех пприложений

opy-dist-front-to-dist-backend

Копирование собранного фронтенд приложения в собранный бэкенд

wait-on

Утилита для проверки и ожидания доступности сайта

docker-compose-full:prod:start

Билд и запуск «Docker Compose» инфраструктуры с бэкендом в виде Docker контейнера и статикой фронтенда отдающуюся через Nginx

docker-compose-full:prod:stop

Остановка «Docker Compose» инфраструктуры и всех приложений

docker-compose-full:prod:only-start

Запуск «Docker Compose» инфраструктуры с бэкендом в виде Docker контейнера и статикой фронтенда отдающуюся через Nginx

docker-compose-full:prod:test:e2e

Запуск E2E-тестов на приложение запущенное через «Docker Compose»

docker:build:server:latest

Сборка Docker образа бэкенда

5. Прогоняем юнит-тесты, затем запускаем всю инфраструктуру со всеми приложениями в watch-режиме и прогоняем E2E-тесты

Команды

npm run test npm run pm2-full:dev:start npm run test:e2e 
Вывод консоли
$ npm run test  > @nestjs-mod-fullstack/source@0.0.0 test > ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=test --skip-nx-cache=true --passWithNoTests --output-style=stream-without-prefixes    > nx run app-angular-rest-sdk:test --passWithNoTests   > nx run app-rest-sdk:test --passWithNoTests   > nx run client:test --passWithNoTests   NX   Running target test for 4 projects    ✔  nx run app-rest-sdk:test (2s)  ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Running target test for 4 projects    ✔  nx run app-angular-rest-sdk:test (2s)   ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Running target test for 4 projects        With additional flags:         --passWithNoTests=true     ✔  nx run client:test (5s)    ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Running target test for 4 projects     ✔  nx run server:test (4s)  ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Successfully ran target test for 4 projects (6s)        With additional flags:         --passWithNoTests=true  $ npm run pm2-full:dev:start  > @nestjs-mod-fullstack/source@0.0.0 pm2-full:dev:start > npm run generate && npm run docker-compose:start-prod:server && npm run db:create && npm run flyway:migrate && npm run pm2:dev:start   > @nestjs-mod-fullstack/source@0.0.0 generate > ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=generate --skip-nx-cache=true && npm run make-ts-list && npm run lint:fix      ✔  nx run server:generate (13s)  ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Successfully ran target generate for project server (13s)    NX   Nx detected a flaky task    server:generate  Flaky tasks can disrupt your CI pipeline. Automatically retry them with Nx Cloud. Learn more at https://nx.dev/ci/features/flaky-tasks   > @nestjs-mod-fullstack/source@0.0.0 make-ts-list > ./node_modules/.bin/rucken make-ts-list   > @nestjs-mod-fullstack/source@0.0.0 lint:fix > npm run tsc:lint && ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=lint --fix   > @nestjs-mod-fullstack/source@0.0.0 tsc:lint > ./node_modules/.bin/tsc --noEmit -p tsconfig.base.json      ✔  nx run app-angular-rest-sdk:lint  [existing outputs match the cache, left as is]    ✔  nx run client:lint  [existing outputs match the cache, left as is]    ✔  nx run server-e2e:lint  [existing outputs match the cache, left as is]    ✔  nx run server:lint (1s)  ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Successfully ran target lint for 4 projects (1s)        With additional flags:         --fix=true  Nx read the output from the cache instead of running the command for 3 out of 4 tasks.   > @nestjs-mod-fullstack/source@0.0.0 docker-compose:start-prod:server > export COMPOSE_INTERACTIVE_NO_CLI=1 && docker-compose -f ./apps/server/docker-compose-prod.yml --env-file ./apps/server/docker-compose-prod.env --compatibility up -d  server-postgre-sql is up-to-date  > @nestjs-mod-fullstack/source@0.0.0 db:create > ./node_modules/.bin/nx run-many -t=db-create      ✔  nx run server:db-create (746ms)  ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Successfully ran target db-create for project server (775ms)   > @nestjs-mod-fullstack/source@0.0.0 flyway:migrate > ./node_modules/.bin/nx run-many -t=flyway-migrate      ✔  nx run server:flyway-migrate (1s)  ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Successfully ran target flyway-migrate for project server (2s)   > @nestjs-mod-fullstack/source@0.0.0 pm2:dev:start > ./node_modules/.bin/pm2 start ./ecosystem.config.json && npm run wait-on -- --log http://localhost:3000/api/health --log http://localhost:4200  [PM2][WARN] Applications server, client not running, starting... [PM2] App [server] launched (1 instances) [PM2] App [client] launched (1 instances) ┌────┬───────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐ │ id │ name      │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │ ├────┼───────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤ │ 1  │ client    │ default     │ N/A     │ fork    │ 175791   │ 0s     │ 0    │ online    │ 0%       │ 13.1mb   │ endy     │ disabled │ │ 0  │ server    │ default     │ N/A     │ fork    │ 175790   │ 0s     │ 0    │ online    │ 0%       │ 18.7mb   │ endy     │ disabled │ └────┴───────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘  > @nestjs-mod-fullstack/source@0.0.0 wait-on > ./node_modules/.bin/wait-on --timeout=240000 --interval=1000 --window --verbose --log http://localhost:3000/api/health --log http://localhost:4200  waiting for 2 resources: http://localhost:3000/api/health, http://localhost:4200 making HTTP(S) head request to  url:http://localhost:3000/api/health ... making HTTP(S) head request to  url:http://localhost:4200 ...   HTTP(S) error for http://localhost:3000/api/health Error: connect ECONNREFUSED 127.0.0.1:3000   HTTP(S) error for http://localhost:4200 Error: connect ECONNREFUSED 127.0.0.1:4200 making HTTP(S) head request to  url:http://localhost:3000/api/health ... making HTTP(S) head request to  url:http://localhost:4200 ...   HTTP(S) error for http://localhost:3000/api/health Error: connect ECONNREFUSED 127.0.0.1:3000   HTTP(S) error for http://localhost:4200 Error: connect ECONNREFUSED 127.0.0.1:4200 making HTTP(S) head request to  url:http://localhost:3000/api/health ... making HTTP(S) head request to  url:http://localhost:4200 ...   HTTP(S) error for http://localhost:3000/api/health Error: connect ECONNREFUSED 127.0.0.1:3000 making HTTP(S) head request to  url:http://localhost:3000/api/health ...   HTTP(S) error for http://localhost:3000/api/health Error: connect ECONNREFUSED 127.0.0.1:3000 making HTTP(S) head request to  url:http://localhost:4200 ... making HTTP(S) head request to  url:http://localhost:3000/api/health ...   HTTP(S) error for http://localhost:3000/api/health Error: connect ECONNREFUSED 127.0.0.1:3000 making HTTP(S) head request to  url:http://localhost:4200 ... making HTTP(S) head request to  url:http://localhost:3000/api/health ... making HTTP(S) head request to  url:http://localhost:4200 ...   HTTP(S) result for http://localhost:3000/api/health: {   status: 200,   statusText: 'OK',   headers: Object [AxiosHeaders] {     'x-powered-by': 'Express',     vary: 'Origin',     'access-control-allow-credentials': 'true',     'x-request-id': '72cc7a93-98b5-4e60-8c4e-65e9458385bf',     'cache-control': 'no-cache, no-store, must-revalidate',     'content-type': 'application/json; charset=utf-8',     'content-length': '107',     etag: 'W/"6b-ouXVoNOXyOxnMfI7caewF8/p97A"',     date: 'Sat, 17 Aug 2024 04:02:41 GMT',     connection: 'keep-alive',     'keep-alive': 'timeout=5'   },   data: '' } waiting for 1 resources: http://localhost:4200 making HTTP(S) head request to  url:http://localhost:4200 ...   HTTP(S) result for http://localhost:4200: {   status: 200,   statusText: 'OK',   headers: Object [AxiosHeaders] {     'x-powered-by': 'Express',     'access-control-allow-origin': '*',     'content-type': 'text/html; charset=utf-8',     'accept-ranges': 'bytes',     'content-length': '586',     date: 'Sat, 17 Aug 2024 04:02:42 GMT',     connection: 'keep-alive',     'keep-alive': 'timeout=5'   },   data: '' } wait-on(175826) complete  $ npm run test:e2e  > @nestjs-mod-fullstack/source@0.0.0 test:e2e > ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=e2e --skip-nx-cache=true --output-style=stream-without-prefixes    > nx run client-e2e:e2e  > playwright test   NX   Running target e2e for 2 projects and 1 task they depend on    NX   Running target e2e for 2 projects and 1 task they depend on     →  Executing 1/3 remaining tasks...     ⠧  nx run client-e2e:e2e    ✔  nx run client-e2e:e2e (7s)  ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————    ✔  nx run server:build:production (3s)  ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————    ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Running target e2e for 2 projects and 1 task they depend on     →  Executing 1/1 remaining tasks...     ⠧  nx run server-e2e:e2e     ✔  2/2 succeeded [0 read from cache]   PASS   server-e2e  apps/server-e2e/src/server/server.spec.ts   GET /api     ✓ should return a message (28 ms)    ✔  nx run server-e2e:e2e (2s)  ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Successfully ran target e2e for 2 projects and 1 task they depend on (12s) 

6. Останавливаем всю инфраструктуру со всеми приложениями в watch-режиме

Команды

npm run pm2-full:dev:stop 
Вывод консоли
$  npm run pm2-full:dev:stop  > @nestjs-mod-fullstack/source@0.0.0 pm2-full:dev:stop > npm run docker-compose:stop-prod:server && npm run pm2:dev:stop   > @nestjs-mod-fullstack/source@0.0.0 docker-compose:stop-prod:server > export COMPOSE_INTERACTIVE_NO_CLI=1 && docker-compose -f ./apps/server/docker-compose-prod.yml --env-file ./apps/server/docker-compose-prod.env down  Stopping server-postgre-sql ... done Removing server-postgre-sql ... done Removing network server_server-network  > @nestjs-mod-fullstack/source@0.0.0 pm2:dev:stop > ./node_modules/.bin/pm2 delete all  [PM2] Applying action deleteProcessId on app [all](ids: [ 0, 1 ]) [PM2] [client](1) ✓ [PM2] [server](0) ✓ ┌────┬───────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐ │ id │ name      │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │ └────┴───────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘ 

7. Прогоняем юнит-тесты, затем запускаем всю инфраструктуру со всеми приложениями через PM2 в собранном режиме и прогоняем E2E-тесты

Команды

npm run test npm run pm2-full:prod:start npm run test:e2e 
Вывод консоли
$ npm run test  > @nestjs-mod-fullstack/source@0.0.0 test > ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=test --skip-nx-cache=true --passWithNoTests --output-style=stream-without-prefixes    > nx run app-angular-rest-sdk:test --passWithNoTests   > nx run app-rest-sdk:test --passWithNoTests   > nx run client:test --passWithNoTests   NX   Running target test for 4 projects    ✔  nx run app-rest-sdk:test (2s)  ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Running target test for 4 projects    ✔  nx run app-angular-rest-sdk:test (2s)   ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Running target test for 4 projects        With additional flags:         --passWithNoTests=true     ✔  nx run client:test (5s)    ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Running target test for 4 projects     ✔  nx run server:test (4s)  ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Successfully ran target test for 4 projects (6s)        With additional flags:         --passWithNoTests=true  $ npm run pm2-full:prod:start  > @nestjs-mod-fullstack/source@0.0.0 pm2-full:prod:start > npm run generate && npm run build -- -c production && npm run copy-front-to-backend && npm run docker-compose:start-prod:server && npm run db:create && npm run flyway:migrate && npm run pm2:start   > @nestjs-mod-fullstack/source@0.0.0 generate > ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=generate --skip-nx-cache=true && npm run make-ts-list && npm run lint:fix      ✔  nx run server:generate (12s)  ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Successfully ran target generate for project server (12s)   > @nestjs-mod-fullstack/source@0.0.0 make-ts-list > ./node_modules/.bin/rucken make-ts-list   > @nestjs-mod-fullstack/source@0.0.0 lint:fix > npm run tsc:lint && ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=lint --fix   > @nestjs-mod-fullstack/source@0.0.0 tsc:lint > ./node_modules/.bin/tsc --noEmit -p tsconfig.base.json      ✔  nx run app-angular-rest-sdk:lint  [existing outputs match the cache, left as is]    ✔  nx run client:lint  [existing outputs match the cache, left as is]    ✔  nx run server:lint  [existing outputs match the cache, left as is]    ✔  nx run server-e2e:lint  [existing outputs match the cache, left as is]  ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Successfully ran target lint for 4 projects (110ms)        With additional flags:         --fix=true  Nx read the output from the cache instead of running the command for 4 out of 4 tasks.   > @nestjs-mod-fullstack/source@0.0.0 build > npm run generate && npm run tsc:lint && ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=build --skip-nx-cache=true -c production   > @nestjs-mod-fullstack/source@0.0.0 generate > ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=generate --skip-nx-cache=true && npm run make-ts-list && npm run lint:fix      ✔  nx run server:generate (12s)  ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Successfully ran target generate for project server (12s)   > @nestjs-mod-fullstack/source@0.0.0 make-ts-list > ./node_modules/.bin/rucken make-ts-list   > @nestjs-mod-fullstack/source@0.0.0 lint:fix > npm run tsc:lint && ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=lint --fix   > @nestjs-mod-fullstack/source@0.0.0 tsc:lint > ./node_modules/.bin/tsc --noEmit -p tsconfig.base.json      ✔  nx run app-angular-rest-sdk:lint  [existing outputs match the cache, left as is]    ✔  nx run client:lint  [existing outputs match the cache, left as is]    ✔  nx run server:lint  [existing outputs match the cache, left as is]    ✔  nx run server-e2e:lint  [existing outputs match the cache, left as is]  ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Successfully ran target lint for 4 projects (113ms)        With additional flags:         --fix=true  Nx read the output from the cache instead of running the command for 4 out of 4 tasks.   > @nestjs-mod-fullstack/source@0.0.0 tsc:lint > ./node_modules/.bin/tsc --noEmit -p tsconfig.base.json      ✔  nx run app-rest-sdk:build (2s)    ✔  nx run app-angular-rest-sdk:build:production (2s)    ✔  nx run server:build:production (4s)    ✔  nx run client:build:production (5s)  ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Successfully ran target build for 4 projects (7s)   > @nestjs-mod-fullstack/source@0.0.0 copy-front-to-backend > rm -rf dist/apps/server/assets/client && cp -r dist/apps/client/browser dist/apps/server/assets/client   > @nestjs-mod-fullstack/source@0.0.0 docker-compose:start-prod:server > export COMPOSE_INTERACTIVE_NO_CLI=1 && docker-compose -f ./apps/server/docker-compose-prod.yml --env-file ./apps/server/docker-compose-prod.env --compatibility up -d  Creating network "server_server-network" with driver "bridge" Creating server-postgre-sql ... done  > @nestjs-mod-fullstack/source@0.0.0 db:create > ./node_modules/.bin/nx run-many -t=db-create      ✔  nx run server:db-create (733ms)  ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Successfully ran target db-create for project server (763ms)   > @nestjs-mod-fullstack/source@0.0.0 flyway:migrate > ./node_modules/.bin/nx run-many -t=flyway-migrate      ✔  nx run server:flyway-migrate (1s)  ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Successfully ran target flyway-migrate for project server (1s)    NX   Nx detected a flaky task    server:flyway-migrate  Flaky tasks can disrupt your CI pipeline. Automatically retry them with Nx Cloud. Learn more at https://nx.dev/ci/features/flaky-tasks   > @nestjs-mod-fullstack/source@0.0.0 pm2:start > ./node_modules/.bin/pm2 start ./ecosystem-prod.config.json && npm run wait-on -- --log http://localhost:3000/api/health --log http://localhost:3000   >>>> In-memory PM2 is out-of-date, do: >>>> $ pm2 update In memory PM2 version: 3.1.3 Local PM2 version: 5.4.2  [PM2][WARN] Applications nestjs-mod-fullstack not running, starting... [PM2] App [nestjs-mod-fullstack] launched (1 instances) ┌────┬─────────────────────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐ │ id │ name                    │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │ ├────┼─────────────────────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤ │ 0  │ nestjs-mod-fullstack    │ default     │ N/A     │ fork    │ 106436   │ 0s     │ 0    │ online    │ 0%       │ 11.6mb   │ endy     │ disabled │ └────┴─────────────────────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘  > @nestjs-mod-fullstack/source@0.0.0 wait-on > ./node_modules/.bin/wait-on --timeout=240000 --interval=1000 --window --verbose --log http://localhost:3000/api/health --log http://localhost:3000  waiting for 2 resources: http://localhost:3000/api/health, http://localhost:3000 making HTTP(S) head request to  url:http://localhost:3000/api/health ... making HTTP(S) head request to  url:http://localhost:3000 ...   HTTP(S) error for http://localhost:3000/api/health Error: connect ECONNREFUSED 127.0.0.1:3000   HTTP(S) error for http://localhost:3000 Error: connect ECONNREFUSED 127.0.0.1:3000 making HTTP(S) head request to  url:http://localhost:3000/api/health ... making HTTP(S) head request to  url:http://localhost:3000 ...   HTTP(S) result for http://localhost:3000/api/health: {   status: 200,   statusText: 'OK',   headers: Object [AxiosHeaders] {     'x-powered-by': 'Express',     vary: 'Origin',     'access-control-allow-credentials': 'true',     'x-request-id': '011863a0-2444-40d4-a012-93c3dd9d3d96',     'cache-control': 'no-cache, no-store, must-revalidate',     'content-type': 'application/json; charset=utf-8',     'content-length': '107',     etag: 'W/"6b-ouXVoNOXyOxnMfI7caewF8/p97A"',     date: 'Tue, 20 Aug 2024 06:04:02 GMT',     connection: 'keep-alive',     'keep-alive': 'timeout=5'   },   data: '' } waiting for 1 resources: http://localhost:3000   HTTP(S) result for http://localhost:3000: {   status: 200,   statusText: 'OK',   headers: Object [AxiosHeaders] {     'x-powered-by': 'Express',     vary: 'Origin',     'access-control-allow-credentials': 'true',     'accept-ranges': 'bytes',     'cache-control': 'public, max-age=0',     'last-modified': 'Tue, 20 Aug 2024 06:03:56 GMT',     etag: 'W/"8e8-1916e62868f"',     'content-type': 'text/html; charset=UTF-8',     'content-length': '2280',     date: 'Tue, 20 Aug 2024 06:04:02 GMT',     connection: 'keep-alive',     'keep-alive': 'timeout=5'   },   data: '' } wait-on(106462) complete  $ npm run test:e2e  > @nestjs-mod-fullstack/source@0.0.0 test:e2e > ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=e2e --skip-nx-cache=true --output-style=stream-without-prefixes    > nx run client-e2e:e2e  > playwright test     NX   Running target e2e for 2 projects and 1 task they depend on    NX   Running target e2e for 2 projects and 1 task they depend on     →  Executing 1/3 remaining tasks...     ⠼  nx run client-e2e:e2e    ✔  nx run client-e2e:e2e (13s)  ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————    ✔  nx run server:build:production (3s)  ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————    ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Running target e2e for 2 projects and 1 task they depend on     →  Executing 1/1 remaining tasks...     ⠦  nx run server-e2e:e2e     ✔  2/2 succeeded [0 read from cache]   PASS   server-e2e  apps/server-e2e/src/server/server.spec.ts   GET /api     ✓ should return a message (27 ms)    ✔  nx run server-e2e:e2e (2s)  ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Successfully ran target e2e for 2 projects and 1 task they depend on (18s)  

8. Останавливаем всю инфраструктуру и все собранные и запущенные через PM2 приложения

Команды

npm run pm2-full:prod:stop 
Вывод консоли
$  npm run pm2-full:prod:stop  > @nestjs-mod-fullstack/source@0.0.0 pm2-full:prod:stop > npm run docker-compose:stop-prod:server && npm run pm2:stop   > @nestjs-mod-fullstack/source@0.0.0 docker-compose:stop-prod:server > export COMPOSE_INTERACTIVE_NO_CLI=1 && docker-compose -f ./apps/server/docker-compose-prod.yml --env-file ./apps/server/docker-compose-prod.env down  Stopping server-postgre-sql ... done Removing server-postgre-sql ... done Removing network server_server-network  > @nestjs-mod-fullstack/source@0.0.0 pm2:stop > ./node_modules/.bin/pm2 delete all  [PM2] Applying action deleteProcessId on app [all](ids: [ 0 ]) [PM2] [nestjs-mod-fullstack](0) ✓ ┌────┬───────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐ │ id │ name      │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │ └────┴───────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘ 

9. Добавляем Docker-файл который собрет образ с запущенным бэкендом

Сборка происходит в несколько этапов:

  1. Устанавливаем только dependencies

  2. Ставим devDependencies необходимые для генерации дополнительного кода и пакетов

  3. Генерируем СДК для Prisma

  4. Удаляем лишние пакеты из node_modules

  5. Копируем node_modules и приложения в новый чистый образ

Создаем файл .docker/server.Dockerfile

 FROM node:20.16.0-alpine AS builder WORKDIR /usr/src/app COPY . . # To work as a PID 1 RUN apk add dumb-init # Remove dev dependencies RUN apk add jq RUN echo $(cat package.json | jq 'del(.devDependencies)') > package.json # Removing unnecessary settings RUN rm -rf nx.json package-lock.json .dockerignore && \     # Replacing the settings     cp .docker/nx.json nx.json && \     cp .docker/.dockerignore .dockerignore && \     # Install dependencies     npm install && \     # Installing utilities to generate additional files     npm install --save-dev nx@19.5.3 prisma@5.18.0 prisma-class-generator@0.2.11 && \     # Some utilities require a ".env" file     echo '' > .env && \     # Generating additional code     npm run prisma:generate && \     # Remove unnecessary packages     rm -rf /usr/src/app/node_modules/@nx && \     rm -rf /usr/src/app/node_modules/@prisma-class-generator && \     rm -rf /usr/src/app/node_modules/@angular  && \     rm -rf /usr/src/app/node_modules/@swc  && \     rm -rf /usr/src/app/node_modules/@babel  && \     rm -rf /usr/src/app/node_modules/@angular-devkit && \     rm -rf /usr/src/app/node_modules/@ngneat && \     rm -rf /usr/src/app/node_modules/@types && \     rm -rf /usr/src/app/node_modules/@ng-packagr  FROM node:20.16.0-alpine WORKDIR /usr/src/app # Copy all project files COPY --from=builder /usr/src/app/ /usr/src/app/ # Copy utility for "To work as a PID 1" COPY --from=builder /usr/bin/dumb-init /usr/bin/dumb-init # Set server port ENV SERVER_PORT=8080 # Share port EXPOSE 8080 # Run server CMD ["dumb-init","node", "dist/apps/server/main.js"]   

10. Собираем образ бэкенда

Скрипт для запуска сборки описан в package.json, так как у нас всего лишь одно приложение которое может собираться в Docker-образ, в дальнейшем после появление новых Docker-приложений команда сборки образа уйдет в project.json

Команды

npm run docker:build:server:latest 
Вывод консоли
$ npm run docker:build:server:latest  > @nestjs-mod-fullstack/source@0.0.0 docker:build:server:latest > docker build -t nestjs-mod-fullstack-server:latest -f ./.docker/server.Dockerfile . --progress=plain  #0 building with "default" instance using docker driver  #1 [internal] load build definition from server.Dockerfile #1 transferring dockerfile: 1.65kB done #1 DONE 0.0s  #2 [internal] load .dockerignore #2 transferring context: 79B done #2 DONE 0.0s  #3 [internal] load metadata for docker.io/library/node:20.16.0-alpine #3 DONE 2.7s  #4 [internal] load build context #4 transferring context: 7.08MB 0.1s done #4 DONE 0.1s  #5 [builder 1/7] FROM docker.io/library/node:20.16.0-alpine@sha256:eb8101caae9ac02229bd64c024919fe3d4504ff7f329da79ca60a04db08cef52 #5 resolve docker.io/library/node:20.16.0-alpine@sha256:eb8101caae9ac02229bd64c024919fe3d4504ff7f329da79ca60a04db08cef52 done #5 sha256:e2997a3fdff8b88aee369a7de727d89bff21c0e2927d7c0487dbbaab6eaf8f14 6.38kB / 6.38kB done #5 sha256:c6a83fedfae6ed8a4f5f7cbb6a7b6f1c1ec3d86fea8cb9e5ba2e5e6673fde9f6 0B / 3.62MB 0.1s #5 sha256:d9aac50bc34e2a0199701ebddca85c36acd90c4d1ad915ca0849364c41547d70 0B / 42.24MB 0.1s #5 sha256:0150f131fd2fb613a281e43d320d5772ad190446bcbb177a28f53838f53fdd3c 0B / 1.39MB 0.1s #5 sha256:eb8101caae9ac02229bd64c024919fe3d4504ff7f329da79ca60a04db08cef52 7.67kB / 7.67kB done #5 sha256:375518d70893d14665b99393079e77bd4947884f123a66ade28744eb8340d229 1.72kB / 1.72kB done #5 sha256:d9aac50bc34e2a0199701ebddca85c36acd90c4d1ad915ca0849364c41547d70 3.15MB / 42.24MB 0.7s #5 sha256:d9aac50bc34e2a0199701ebddca85c36acd90c4d1ad915ca0849364c41547d70 7.34MB / 42.24MB 1.1s #5 sha256:c6a83fedfae6ed8a4f5f7cbb6a7b6f1c1ec3d86fea8cb9e5ba2e5e6673fde9f6 1.05MB / 3.62MB 1.3s #5 sha256:0150f131fd2fb613a281e43d320d5772ad190446bcbb177a28f53838f53fdd3c 1.05MB / 1.39MB 1.4s #5 sha256:c6a83fedfae6ed8a4f5f7cbb6a7b6f1c1ec3d86fea8cb9e5ba2e5e6673fde9f6 2.10MB / 3.62MB 1.6s #5 sha256:0150f131fd2fb613a281e43d320d5772ad190446bcbb177a28f53838f53fdd3c 1.39MB / 1.39MB 1.5s done #5 sha256:c0ce3bd8f30377d0ed394d1177e5009ffc3f6907a980562779583174e8b04acc 0B / 446B 1.6s #5 sha256:d9aac50bc34e2a0199701ebddca85c36acd90c4d1ad915ca0849364c41547d70 10.49MB / 42.24MB 1.7s #5 sha256:c6a83fedfae6ed8a4f5f7cbb6a7b6f1c1ec3d86fea8cb9e5ba2e5e6673fde9f6 3.15MB / 3.62MB 1.8s #5 extracting sha256:c6a83fedfae6ed8a4f5f7cbb6a7b6f1c1ec3d86fea8cb9e5ba2e5e6673fde9f6 #5 sha256:c6a83fedfae6ed8a4f5f7cbb6a7b6f1c1ec3d86fea8cb9e5ba2e5e6673fde9f6 3.62MB / 3.62MB 1.8s done #5 extracting sha256:c6a83fedfae6ed8a4f5f7cbb6a7b6f1c1ec3d86fea8cb9e5ba2e5e6673fde9f6 0.1s done #5 sha256:d9aac50bc34e2a0199701ebddca85c36acd90c4d1ad915ca0849364c41547d70 14.68MB / 42.24MB 2.1s #5 sha256:c0ce3bd8f30377d0ed394d1177e5009ffc3f6907a980562779583174e8b04acc 446B / 446B 2.0s done #5 sha256:d9aac50bc34e2a0199701ebddca85c36acd90c4d1ad915ca0849364c41547d70 17.83MB / 42.24MB 2.4s #5 sha256:d9aac50bc34e2a0199701ebddca85c36acd90c4d1ad915ca0849364c41547d70 20.97MB / 42.24MB 2.6s #5 sha256:d9aac50bc34e2a0199701ebddca85c36acd90c4d1ad915ca0849364c41547d70 24.12MB / 42.24MB 2.9s #5 sha256:d9aac50bc34e2a0199701ebddca85c36acd90c4d1ad915ca0849364c41547d70 28.31MB / 42.24MB 3.3s #5 sha256:d9aac50bc34e2a0199701ebddca85c36acd90c4d1ad915ca0849364c41547d70 32.51MB / 42.24MB 3.6s #5 sha256:d9aac50bc34e2a0199701ebddca85c36acd90c4d1ad915ca0849364c41547d70 35.65MB / 42.24MB 3.9s #5 sha256:d9aac50bc34e2a0199701ebddca85c36acd90c4d1ad915ca0849364c41547d70 39.85MB / 42.24MB 4.2s #5 sha256:d9aac50bc34e2a0199701ebddca85c36acd90c4d1ad915ca0849364c41547d70 42.24MB / 42.24MB 4.4s #5 sha256:d9aac50bc34e2a0199701ebddca85c36acd90c4d1ad915ca0849364c41547d70 42.24MB / 42.24MB 4.4s done #5 extracting sha256:d9aac50bc34e2a0199701ebddca85c36acd90c4d1ad915ca0849364c41547d70 0.1s #5 extracting sha256:d9aac50bc34e2a0199701ebddca85c36acd90c4d1ad915ca0849364c41547d70 1.4s done #5 extracting sha256:0150f131fd2fb613a281e43d320d5772ad190446bcbb177a28f53838f53fdd3c 0.0s done #5 extracting sha256:c0ce3bd8f30377d0ed394d1177e5009ffc3f6907a980562779583174e8b04acc done #5 DONE 6.0s  #6 [builder 2/7] WORKDIR /usr/src/app #6 DONE 0.2s  #7 [builder 3/7] COPY . . #7 DONE 0.0s  #8 [builder 4/7] RUN apk add dumb-init #8 0.175 fetch https://dl-cdn.alpinelinux.org/alpine/v3.20/main/x86_64/APKINDEX.tar.gz #8 0.739 fetch https://dl-cdn.alpinelinux.org/alpine/v3.20/community/x86_64/APKINDEX.tar.gz #8 1.241 (1/1) Installing dumb-init (1.2.5-r3) #8 1.292 Executing busybox-1.36.1-r29.trigger #8 1.298 OK: 11 MiB in 17 packages #8 DONE 1.4s  #9 [builder 5/7] RUN apk add jq #9 0.504 (1/2) Installing oniguruma (6.9.9-r0) #9 1.036 (2/2) Installing jq (1.7.1-r0) #9 1.178 Executing busybox-1.36.1-r29.trigger #9 1.183 OK: 12 MiB in 19 packages #9 DONE 1.3s  #10 [builder 6/7] RUN echo $(cat package.json | jq 'del(.devDependencies)') > package.json #10 DONE 0.3s  #11 [builder 7/7] RUN rm -rf nx.json package-lock.json .dockerignore &&     cp .docker/nx.json nx.json &&     cp .docker/.dockerignore .dockerignore &&     npm install &&     npm install --save-dev nx@19.5.3 prisma@5.18.0 prisma-class-generator@0.2.11 &&     echo '' > .env &&     npm run prisma:generate &&     rm -rf /usr/src/app/node_modules/@nx &&     rm -rf /usr/src/app/node_modules/@prisma-class-generator &&     rm -rf /usr/src/app/node_modules/@angular  &&     rm -rf /usr/src/app/node_modules/@swc  &&     rm -rf /usr/src/app/node_modules/@babel  &&     rm -rf /usr/src/app/node_modules/@angular-devkit &&     rm -rf /usr/src/app/node_modules/@ngneat &&     rm -rf /usr/src/app/node_modules/@types &&     rm -rf /usr/src/app/node_modules/@ng-packagr #11 51.71 #11 51.71 added 408 packages, and audited 409 packages in 51s #11 51.72 #11 51.72 53 packages are looking for funding #11 51.72   run `npm fund` for details #11 51.72 #11 51.72 1 moderate severity vulnerability #11 51.72 #11 51.72 To address all issues, run: #11 51.72   npm audit fix --force #11 51.72 #11 51.72 Run `npm audit` for details. #11 51.72 npm notice #11 51.72 npm notice New patch version of npm available! 10.8.1 -> 10.8.2 #11 51.72 npm notice Changelog: https://github.com/npm/cli/releases/tag/v10.8.2 #11 51.72 npm notice To update run: npm install -g npm@10.8.2 #11 51.72 npm notice #11 67.47 #11 67.47 added 106 packages, and audited 515 packages in 16s #11 67.47 #11 67.47 66 packages are looking for funding #11 67.47   run `npm fund` for details #11 67.47 #11 67.47 1 moderate severity vulnerability #11 67.47 #11 67.47 To address all issues, run: #11 67.47   npm audit fix --force #11 67.47 #11 67.47 Run `npm audit` for details. #11 67.64 #11 67.64 > @nestjs-mod-fullstack/source@0.0.0 prisma:generate #11 67.64 > ./node_modules/.bin/nx run-many -t=prisma-generate #11 67.64 #11 68.24 #11 68.24  NX   Running target prisma-generate for project server: #11 68.24 #11 68.24 - server #11 68.24 #11 68.24 #11 71.85 #11 71.85 > nx run server:prisma-generate #11 71.85 #11 71.85 > ./node_modules/.bin/prisma generate --schema=./apps/server/src/prisma/app-schema.prisma #11 71.85 #11 71.85 Environment variables loaded from .env #11 71.85 Prisma schema loaded from apps/server/src/prisma/app-schema.prisma #11 71.85 prisma:info [Prisma Class Generator]:Handler Registered. #11 71.85 prisma:info [Prisma Class Generator]:Generate /usr/src/app/apps/server/src/app/generated/rest/dto/app_demo.ts #11 71.85 prisma:info [Prisma Class Generator]:Generate /usr/src/app/apps/server/src/app/generated/rest/dto/migrations.ts #11 71.85 #11 71.85 ✔ Generated Prisma Client (v5.18.0, engine=binary) to ./node_modules/@prisma/app-client in 81ms #11 71.85 #11 71.85 ✔ Generated Prisma Class Generator to ./apps/server/src/app/generated/rest/dto in 92ms #11 71.85 #11 71.85 Start by importing your Prisma Client (See: http://pris.ly/d/importing-client) #11 71.85 #11 71.85 Tip: Want to react to database changes in your app as they happen? Discover how with Pulse: https://pris.ly/tip-1-pulse #11 71.85 #11 71.85 #11 71.85 #11 71.85 #11 71.85  NX   Successfully ran target prisma-generate for project server #11 71.85 #11 71.85 #11 DONE 72.5s  #12 [stage-1 3/4] COPY --from=builder /usr/src/app/ /usr/src/app/ #12 DONE 2.1s  #13 [stage-1 4/4] COPY --from=builder /usr/bin/dumb-init /usr/bin/dumb-init #13 DONE 0.0s  #14 exporting to image #14 exporting layers #14 exporting layers 1.7s done #14 writing image sha256:96ba78126a32f2aaa3cdf6a793ad2adbee5077adb7dcded7ca3cef270d68fbfe #14 writing image sha256:96ba78126a32f2aaa3cdf6a793ad2adbee5077adb7dcded7ca3cef270d68fbfe done #14 naming to docker.io/library/nestjs-mod-fullstack-server:latest done #14 DONE 1.7s 

11. Добавляем Nginx-кофиг файл для работы с фронтенд и бэкенд через единую точку входа

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

Создаем файл .docker/nginx/nginx.conf

map $sent_http_content_type $expires {     "text/html" epoch;     "text/html; charset=utf-8" epoch;     default off; }  map $http_upgrade $connection_upgrade {     default upgrade;     '' close; }  upstream nestjs-mod-fullstack-server {     server nestjs-mod-fullstack-server:8080; }  server {     listen 8080;     server_name localhost;      gzip on;     gzip_proxied any;     gzip_types text/plain application/xml text/css application/javascript application/json;     gzip_min_length 1000;     gzip_vary on;     gzip_disable "MSIE [1-6]\.(?!.*SV1)";      client_max_body_size 50m;     proxy_connect_timeout 5m;     proxy_send_timeout 5m;     proxy_read_timeout 5m;     send_timeout 5m;      proxy_max_temp_file_size 0;      root /usr/share/nginx/html;     index index.html;       location /api {         proxy_pass http://nestjs-mod-fullstack-server;         proxy_http_version 1.1;         proxy_set_header Upgrade $http_upgrade;         proxy_set_header Connection $connection_upgrade;         proxy_set_header Host $host;         proxy_set_header Origin $http_origin;         proxy_set_header X-Real-IP $remote_addr;         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;          # kill cache         add_header Last-Modified $date_gmt;         add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';         if_modified_since off;         expires off;         etag off;     }      location / {         expires $expires;         proxy_redirect off;         proxy_set_header Host $host;         proxy_set_header Origin $http_origin;         proxy_set_header X-Real-IP $remote_addr;         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;         proxy_set_header X-Forwarded-Proto $scheme;         proxy_read_timeout 1m;         proxy_connect_timeout 1m;         proxy_intercept_errors on;         error_page 404 =200 /index.html;         root /usr/share/nginx/html;     } }  

12. Добавляем новый «Docker Compose»-файл с одной точкой входа который запустит инфраструктуру и все приложения

В данный момент запустится 3 контейнера:

  1. Сервер базы данных

  2. Контейнер для создания баз данных приложений и наполнения их через миграции приложений

  3. Бэкенд-приложение

  4. Nginx с собранными файлами фронтенда для маршрутизации запросов на бэкенд

Создаем файл .docker/docker-compose-full.yml

version: '3' networks:   nestjs-mod-fullstack-network:     driver: 'bridge' services:   nestjs-mod-fullstack-postgre-sql:     image: 'bitnami/postgresql:15.5.0'     container_name: 'nestjs-mod-fullstack-postgre-sql'     networks:       - 'nestjs-mod-fullstack-network'     volumes:       - 'nestjs-mod-fullstack-postgre-sql-volume:/bitnami/postgresql'     ports:       - '5432:5432'     healthcheck:       test:         - 'CMD-SHELL'         - 'pg_isready -U postgres'       interval: '5s'       timeout: '5s'       retries: 5     tty: true     restart: 'always'     environment:       POSTGRESQL_USERNAME: '${SERVER_POSTGRE_SQL_POSTGRESQL_USERNAME}'       POSTGRESQL_PASSWORD: '${SERVER_POSTGRE_SQL_POSTGRESQL_PASSWORD}'       POSTGRESQL_DATABASE: '${SERVER_POSTGRE_SQL_POSTGRESQL_DATABASE}'   nestjs-mod-fullstack-postgre-sql-migrations:     image: 'node:20-bullseye-slim'     container_name: 'nestjs-mod-fullstack-postgre-sql-migrations'     networks:       - 'nestjs-mod-fullstack-network'     working_dir: '/app'     volumes:       - './../:/app'     command: 'npm run db:create && npm run flyway:migrate'     tty: true     environment:       NX_SKIP_NX_CACHE: 'true'       SERVER_ROOT_DATABASE_URL: '${SERVER_ROOT_DATABASE_URL}'       SERVER_APP_DATABASE_URL: '${SERVER_APP_DATABASE_URL}'     depends_on:       nestjs-mod-fullstack-postgre-sql:         condition: 'service_healthy'   nestjs-mod-fullstack-server:     image: 'nestjs-mod-fullstack-server:latest'     container_name: 'nestjs-mod-fullstack-server'     networks:       - 'nestjs-mod-fullstack-network'     healthcheck:       test: ['CMD-SHELL', 'npx -y wait-on --timeout= --interval=1000 --window --verbose --log http://localhost:8080/api/health']       interval: 30s       timeout: 10s       retries: 10     tty: true     environment:       SERVER_APP_DATABASE_URL: '${SERVER_APP_DATABASE_URL}'     restart: 'always'     depends_on:       nestjs-mod-fullstack-postgre-sql:         condition: service_healthy       nestjs-mod-fullstack-postgre-sql-migrations:         condition: service_completed_successfully   nestjs-mod-fullstack-nginx:     image: nginx:alpine     container_name: 'nestjs-mod-fullstack-nginx'     networks:       - 'nestjs-mod-fullstack-network'     volumes:       - ../.docker/nginx:/etc/nginx/conf.d       - ../dist/apps/client/browser:/usr/share/nginx/html     depends_on:       nestjs-mod-fullstack-server:         condition: service_healthy     ports:       - '8080:8080' volumes:   nestjs-mod-fullstack-postgre-sql-volume:     name: 'nestjs-mod-fullstack-postgre-sql-volume' 

13. Создаем новый файл с переменными окружения, где вместо названий серверов с localhost будут стоять имена доккер контейнеров

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

При деплое на выделенный сервер переменный окружения берутся не из файла который лежит внутри репозитория, а из переменных окружения сервера.

Создаем файл .docker/docker-compose-full.env

SERVER_ROOT_DATABASE_URL=postgres://postgres:postgres_password@nestjs-mod-fullstack-postgre-sql:5432/postgres?schema=public SERVER_APP_DATABASE_URL=postgres://app:app_password@nestjs-mod-fullstack-postgre-sql:5432/app?schema=public SERVER_POSTGRE_SQL_POSTGRESQL_USERNAME=postgres SERVER_POSTGRE_SQL_POSTGRESQL_PASSWORD=postgres_password SERVER_POSTGRE_SQL_POSTGRESQL_DATABASE=postgres 

14. Создаем файл с переменными окружения для watch-режима в Angular-приложении

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

Создаем файл apps/client/src/environments/environment.ts

export const serverUrl = 'http://localhost:3000'; 

15. Создаем файл с переменными окружения для продакшен режима в Angular-приложении

Так как фронтенд и бэкенд находятся на одном домене, адрес сервера оставляем пустым и фронтенд будет работать с бэкендом по адресу /api.

Если фронтенд и бэкенд деплоятся на разные домены, то необходимо указать домен и настроить CORS-политики на бэкенде и nginx, в данных постах этот момент опущен для упрощения понимания происходящего.

Создаем файл apps/client/src/environments/environment.prod.ts

export const serverUrl = ''; 

16. Добавляем правила замены файлов при сборке Angular-приложения в продакшен режиме

Конфиг очень большой, поэтому ниже показываем только то что добавилось.

Добавляем несколько строк в файл apps/client/project.json

{   // ...   "targets": {     "build": {       // ...       "configurations": {         "production": {           // ...           "fileReplacements": [             {               "replace": "apps/client/src/environments/environment.ts",               "with": "apps/client/src/environments/environment.prod.ts"             }           ]         }       }     }   } } 

17. Обновляем конфигурацию Angular-приложения для поддерждки нескольких переменных окружения

Обновляем файл apps/client/src/app/app.config.ts

import { provideHttpClient } from '@angular/common/http'; import { ApplicationConfig, importProvidersFrom, provideZoneChangeDetection } from '@angular/core'; import { provideClientHydration } from '@angular/platform-browser'; import { provideRouter } from '@angular/router'; import { RestClientApiModule, RestClientConfiguration } from '@nestjs-mod-fullstack/app-angular-rest-sdk'; import { appRoutes } from './app.routes'; import { serverUrl } from '../environments/environment';  export const appConfig: ApplicationConfig = {   providers: [     provideClientHydration(),     provideZoneChangeDetection({ eventCoalescing: true }),     provideRouter(appRoutes),     provideHttpClient(),     importProvidersFrom(       RestClientApiModule.forRoot(         () =>           new RestClientConfiguration({             basePath: serverUrl,           })       )     ),   ], }; 

18. Прогоняем юнит-тесты и запускаем приложения в watch-режиме через PM2 с последующей проверкой приложений через E2E-тесты

Команды

npm run test npm run pm2-full:dev:start npm run test:e2e npm run pm2-full:dev:stop 

19. Прогоняем юнит-тесты и запускаем приложения в прод-режиме через PM2 с последующей проверкой приложений через E2E-тесты

Команды

npm run test npm run pm2-full:prod:start npm run test:e2e npm run pm2-full:prod:stop 

20. Меняем настройки E2E-тестов для бэкенда, так как в прод-режиме через «Docker Compose» приложения имеют единую точку входа и порт отличается от того что указан в watch-режиме

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

Обновленный файл apps/server-e2e/src/support/test-setup.ts

/* eslint-disable */  import axios from 'axios';  module.exports = async function () {   // Configure axios for tests to use.   const host = process.env.HOST ?? 'localhost';   const port = process.env.PORT ?? '3000';    axios.defaults.baseURL = process.env['BASE_URL'] || `http://${host}:${port}`; }; 

21. Прогоняем юнит-тесты и запускаем приложения в прод-режиме через «Docker Compose» с последующей проверкой приложений через E2E-тесты

Команды

npm run test npm run docker-compose-full:prod:start npm run docker-compose-full:prod:test:e2e npm run docker-compose-full:prod:stop 

22. После текущих разработок и перед коммитом, прогоняем все генерации, форматирование кода и прогон юнит-тестов

Команды

npm run manual:prepare 
Вывод консоли
$ npm run manual:prepare   > @nestjs-mod-fullstack/source@0.0.0 manual:prepare > npm run generate && npm run docs:infrastructure && npm run test   > @nestjs-mod-fullstack/source@0.0.0 generate > ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=generate --skip-nx-cache=true && npm run make-ts-list && npm run lint:fix      ✔  nx run server:generate (15s)  ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Successfully ran target generate for project server (15s)   > @nestjs-mod-fullstack/source@0.0.0 make-ts-list > ./node_modules/.bin/rucken make-ts-list   > @nestjs-mod-fullstack/source@0.0.0 lint:fix > npm run tsc:lint && ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=lint --fix   > @nestjs-mod-fullstack/source@0.0.0 tsc:lint > ./node_modules/.bin/tsc --noEmit -p tsconfig.base.json      ✔  nx run app-angular-rest-sdk:lint  [existing outputs match the cache, left as is]    ✔  nx run client:lint  [existing outputs match the cache, left as is]    ✔  nx run server-e2e:lint (1s)    ✔  nx run server:lint (1s)  ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Successfully ran target lint for 4 projects (1s)        With additional flags:         --fix=true  Nx read the output from the cache instead of running the command for 2 out of 4 tasks.   > @nestjs-mod-fullstack/source@0.0.0 docs:infrastructure > export NESTJS_MODE=infrastructure && ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source,client* --all -t=serve --parallel=1 -- --watch=false --inspect=false    NX   Running target serve for project server:  - server  With additional flags:   --watch=false   --inspect=false  ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————  > nx run server:serve:development --watch=false --inspect=false  chunk (runtime: main) main.js (main) 12.5 KiB [entry] [rendered] webpack compiled successfully (1e208138c6e6150d) [11:17:23.908] INFO (163227): Starting Nest application...     context: "NestFactory" [11:17:23.908] INFO (163227): DefaultNestApp dependencies initialized     context: "InstanceLoader" [11:17:23.908] INFO (163227): ProjectUtilsSettings dependencies initialized     context: "InstanceLoader" [11:17:23.908] INFO (163227): DefaultNestApplicationInitializerSettings dependencies initialized     context: "InstanceLoader" [11:17:23.908] INFO (163227): DefaultNestApplicationInitializerShared dependencies initialized     context: "InstanceLoader" [11:17:23.908] INFO (163227): NestjsPinoLoggerModuleSettings dependencies initialized     context: "InstanceLoader" [11:17:23.908] INFO (163227): NestjsPinoLoggerModuleShared dependencies initialized     context: "InstanceLoader" [11:17:23.908] INFO (163227): TerminusHealthCheckModuleSettings dependencies initialized     context: "InstanceLoader" [11:17:23.908] INFO (163227): DefaultNestApplicationListenerSettings dependencies initialized     context: "InstanceLoader" [11:17:23.908] INFO (163227): DefaultNestApplicationListenerShared dependencies initialized     context: "InstanceLoader" [11:17:23.908] INFO (163227): PrismaModuleSettings dependencies initialized     context: "InstanceLoader" [11:17:23.908] INFO (163227): AppModuleSettings dependencies initialized     context: "InstanceLoader" [11:17:23.908] INFO (163227): AppModuleShared dependencies initialized     context: "InstanceLoader" [11:17:23.908] INFO (163227): PrismaModule dependencies initialized     context: "InstanceLoader" [11:17:23.908] INFO (163227): InfrastructureMarkdownReportGeneratorSettings dependencies initialized     context: "InstanceLoader" [11:17:23.908] INFO (163227): Pm2Settings dependencies initialized     context: "InstanceLoader" [11:17:23.908] INFO (163227): Pm2Shared dependencies initialized     context: "InstanceLoader" [11:17:23.908] INFO (163227): ProjectUtils dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): DockerComposeSettings dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): ProjectUtils dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): DockerComposePostgreSQLSettings dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): DockerCompose dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): DockerComposePostgreSQL dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): DockerComposePostgreSQLSettings dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): DockerComposePostgreSQLShared dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): FlywaySettings dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): FlywayShared dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): PrismaModuleSettings dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): PrismaModuleShared dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): ProjectUtils dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): InfrastructureMarkdownReportGeneratorSettings dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): ProjectUtils dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): InfrastructureMarkdownReportStorage dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): InfrastructureMarkdownReportStorageSettings dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): ProjectUtils dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): DockerCompose dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): FlywaySettings dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): FlywayShared dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): ProjectUtils dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): DefaultNestApplicationListenerSettings dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): DefaultNestApplicationListenerShared dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): DockerComposeShared dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): InfrastructureMarkdownReportStorageShared dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): ProjectUtils dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): DefaultNestApplicationInitializer dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): DefaultNestApplicationListener dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): PrismaModule dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): InfrastructureMarkdownReportGenerator dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): DockerComposePostgreSQL dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): Flyway dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): DefaultNestApplicationListener dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): NestjsPinoLoggerModule dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): TerminusModule dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): TerminusModule dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): ServeStaticModule dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): ProjectUtilsShared dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): InfrastructureMarkdownReportGeneratorShared dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): Pm2 dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): DockerCompose dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): DockerComposePostgreSQL dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): PrismaModule dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): InfrastructureMarkdownReportGeneratorShared dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): Flyway dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): InfrastructureMarkdownReportGenerator dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): LoggerModule dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): DockerComposePostgreSQLShared dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): PrismaModuleShared dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): TerminusHealthCheckModuleShared dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): TerminusHealthCheckModule dependencies initialized     context: "InstanceLoader" [11:17:23.909] INFO (163227): AppModule dependencies initialized     context: "InstanceLoader" [11:17:23.927] INFO (163227): TerminusHealthCheckController {/api/health}:     context: "RoutesResolver" [11:17:23.929] INFO (163227): Mapped {/api/health, GET} route     context: "RouterExplorer" [11:17:23.929] INFO (163227): AppController {/api}:     context: "RoutesResolver" [11:17:23.929] INFO (163227): Mapped {/api, GET} route     context: "RouterExplorer" [11:17:23.929] INFO (163227): Mapped {/api/demo, POST} route     context: "RouterExplorer" [11:17:23.929] INFO (163227): Mapped {/api/demo/:id, GET} route     context: "RouterExplorer" [11:17:23.930] INFO (163227): Mapped {/api/demo/:id, DELETE} route     context: "RouterExplorer" [11:17:23.930] INFO (163227): Mapped {/api/demo, GET} route     context: "RouterExplorer" [11:17:23.932] INFO (163227): Connected to database!     context: "PrismaClient" [11:17:23.964] DEBUG (163227):     0: "SERVER_ROOT_DATABASE_URL: Description='Connection string for PostgreSQL with root credentials (example: postgres://postgres:postgres_password@localhost:5432/postgres?schema=public, username must be \"postgres\")', Original Name='rootDatabaseUrl'"     1: "SERVER_PORT: Description='The port on which to run the server.', Default='3000', Original Name='port'"     2: "SERVER_HOSTNAME: Description='Hostname on which to listen for incoming packets.', Original Name='hostname'"     3: "SERVER_APP_DATABASE_URL: Description='Connection string for PostgreSQL with module credentials (example: postgres://feat:feat_password@localhost:5432/feat?schema=public)', Original Name='databaseUrl'"     context: "All application environments" [11:17:23.997] INFO (163227): Nest application successfully started     context: "NestApplication"  ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Successfully ran target serve for project server    > @nestjs-mod-fullstack/source@0.0.0 test > ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=test --skip-nx-cache=true --passWithNoTests --output-style=stream-without-prefixes    > nx run app-angular-rest-sdk:test --passWithNoTests   > nx run app-rest-sdk:test --passWithNoTests   > nx run client:test --passWithNoTests      ✔  nx run app-angular-rest-sdk:test (2s)  ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Running target test for 4 projects    ✔  nx run app-rest-sdk:test (2s)   ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Running target test for 4 projects        With additional flags:         --passWithNoTests=true     →  Executing 2/2 remaining tasks in parallel...    ✔  nx run client:test (7s)   ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Running target test for 4 projects     ✔  nx run server:test (5s)  ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————   NX   Successfully ran target test for 4 projects (7s)        With additional flags:         --passWithNoTests=true 

В следующем посте я добавлю деплой на выделенный сервер в двух режимах PM2 (будет работать на определенном порту) и «Docker Compose» (будет работать на поддомене)…

Ссылки

https://nestjs.com — официальный сайт фреймворка
https://nestjs-mod.com — официальный сайт дополнительных утилит
https://github.com/nestjs-mod/nestjs-mod-fullstack — проект из поста
https://github.com/nestjs-mod/nestjs-mod-fullstack/commit/d97b4121e910627e19fa55f01919557ae898dc42 — коммит на текущие изменения


ссылка на оригинал статьи https://habr.com/ru/articles/838830/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *