Skip to content

vitalyvitmens/AngularNestJS_Full-stack

Repository files navigation

AngularNestJS_Full-stack

backend & frontend ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅:

  • backend Π½Π° Π±Π°Π·Π΅ NestJS, Π² качСствС Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… выступаСт PostgreSQL,
    для управлСния Π±Π°Π·ΠΎΠΉ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ TypeORM, Π² качСствС языка запроса Ρƒ backend ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ GraphQL.
  • frontend Π½Π° Π±Π°Π·Π΅ Angular.

    ВсС это ΡƒΠΏΠ°ΠΊΠΎΠ²Π°Π½ΠΎ Π² docker-compose!

ΠœΠ΅Ρ‚ΠΎΠ΄ установки ΠΈ запуска:

Π‘ΠΊΠΎΠΏΠΈΡ€ΡƒΠΉΡ‚Π΅ ΠΊ сСбС Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ:
https://github.com/vitalyvitmens/AngularNestJS_Full-stack

Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ Π² ΠΊΠΎΡ€Π½Π΅ рСпозитория .env Ρ„Π°ΠΉΠ», Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€:

API_PORT=3001
API_HOST=http://localhost:
TYPEORM_CONNECTION=postgres
TYPEORM_USERNAME=admin
TYPEORM_PASSWORD=123456
TYPEORM_DATABASE=AngularNestJS_Full-stack
TYPEORM_PORT=5432
TYPEORM_HOST=localhost

ΠšΠΎΠΌΠ°Π½Π΄Ρ‹ для Docker:

docker-compose up
-d - для запуска Π² Ρ„ΠΎΠ½Π΅
--build - для ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎΠΉ пСрСсборки ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ΠΎΠ²
docker ps - ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π·Π°ΠΏΡƒΡ‰Π΅Π½Π½Ρ‹Π΅ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Ρ‹

Backend:

cd backend/
yarn install
yarn start

Frontend:

cd frontend/
yarn install
yarn start

Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ с нуля ΠΏΠΎΠ΄ΠΎΠ±Π½ΠΎΠ΅ backend & frontend ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅:

Π‘ΠΎΠ·Π΄Π°Ρ‘ΠΌ backend ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π½Π° Π±Π°Π·Π΅ NestJS:

УстанавливаСм NestJS ΠΈ ΠΏΠ°ΠΊΠ΅Ρ‚Π½Ρ‹ΠΉ ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€ Yarn Π½Π° ΠΊΠΎΠΌΠΏ:

npm i -g @nestjs/cli
npm install --global yarn

Π‘ΠΎΠ·Π΄Π°Ρ‘ΠΌ ΠΏΠ°ΠΏΠΊΡƒ с нашим ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΎΠΌ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ AngularNestJS_Full-stack ΠΈ ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ΠΈΠΌ Π² Π½Π΅Π΅ для создания сСрвСрной части прилоТСния (Π² Π΄Π°Π½Π½ΠΎΠΌ случаС это ΠΏΠ°ΠΏΠΊΠ° backend):

nest new backend --package-manager=yarn

Π’Π½ΡƒΡ‚Ρ€ΠΈ ΠΏΠ°ΠΏΠΊΠΈ backend удаляСм ΡΠΊΡ€Ρ‹Ρ‚ΡƒΡŽ ΠΏΠ°ΠΏΠΊΡƒ git

ΠžΡ‚ΠΊΡ€Ρ‹Π²Π°Π΅ΠΌ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ Π² своСй срСдС Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Visual Studio Code ΠΈ стартуСм backend ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ Π΅Π³ΠΎ Ρ€Π°Π±ΠΎΡ‚ΠΎΡΠΏΠΎΡΠΎΠ±Π½ΠΎΡΡ‚ΡŒ Π½Π° Π΄Π°Π½Π½ΠΎΠΌ этапС:

cd backend/
yarn start

Π’ случаС успСха, ошибок Π² Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π»Π΅ Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚, Π° само ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ½ΠΎ ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ Π½Π° http://localhost:3000/
Π§Ρ‚ΠΎΠ±Ρ‹ ΠΎΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, Π² Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π»Π΅ Π½Π°ΠΆΠΌΠΈΡ‚Π΅: Ctrl + C

НастраиваСм ΠΊΠΎΡ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡŽ нашСго оборудования, создаём file .env:

cd ..
touch .env    //Π² случаС Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π»Π° Ubuntu (WSL)
echo $null >> .env    //Π² случаС Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π»Π° powershell

Π—Π°Ρ…ΠΎΠ΄ΠΈΠΌ Π² Ρ„Π°ΠΉΠ» .env ΠΈ прописываСм ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡŽ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€:

API_PORT=3001
API_HOST=http://localhost:
TYPEORM_CONNECTION=postgres
TYPEORM_USERNAME=admin
TYPEORM_PASSWORD=123456
TYPEORM_DATABASE=AngularNestJS_Full-stack
TYPEORM_PORT=5432
TYPEORM_HOST=localhost

ДобавляСм ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡŽ Π² нашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ сСрвСрной части (backend):

cd backend/
yarn add @nestjs/config

Π—Π°Ρ…ΠΎΠ΄ΠΈΠΌ Π² Ρ„Π°ΠΉΠ» main.ts создаСм ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅: config ΠΈ port. ΠŸΡ€ΠΈΠΌΠ΅Ρ€Π½Ρ‹ΠΉ ΠΊΠΎΠ΄:

import { ConfigService } from '@nestjs/config';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  const config = await app.get(ConfigService);
  const port = config.get<number>('API_PORT');
  await app.listen(port || 3000, () => {
    console.log(`App started on port: ${port}`);
  });
}
bootstrap();

ΠŸΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ΠΈΠΌ Π² Ρ„Π°ΠΉΠ» app.module.ts ΠΈ Ρ‡Π΅Ρ€Π΅Π· imports ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ConfigModule:

ConfigModule.forRoot({
  isGlobal: true,
  envFilePath: '../.env',
}),

ЗапускаСм ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Ρ‡Ρ‚ΠΎΠ±Ρ‹ убСдится, Ρ‡Ρ‚ΠΎ всС Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚:

cd backend/
nest start --watch

Π’ случаС успСха Π² Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π»Π΅ появится тСкст:
App started on port: 3001

НастраиваСм Π±Π°Π·Ρƒ Π΄Π°Π½Π½Ρ‹Ρ… PostgreSQL, которая Π±ΡƒΠ΄Π΅Ρ‚ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒΡΡ Ρ‡Π΅Ρ€Π΅Π· Docker:

  • Π² ΠΊΠΎΡ€Π½Π΅ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° создаСм Ρ„Π°ΠΉΠ» docker-compose.yml:

    cd .. touch docker-compose.yml //Π² случаС Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π»Π° Ubuntu (WSL) echo $null >> docker-compose.yml //Π² случаС Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π»Π° powershell

Π—Π°Ρ…ΠΎΠ΄ΠΈΠΌ Π² Ρ„Π°ΠΉΠ» docker-compose.yml ΠΈ настраиваСм Π΅Π³ΠΎ. ΠŸΡ€ΠΈΠΌΠ΅Ρ€Π½Ρ‹ΠΉ ΠΊΠΎΠ΄:

version: '3.8'

services:
  db:
    container_name: postgres-AngularNestJS_Full-stack
    image: postgres
    restart: always
    environment:
      - POSTGRES_USER=${TYPEORM_USERNAME}
      - POSTGRES_PASSWORD=${TYPEORM_PASSWORD}
      - POSTGRES_DB=${TYPEORM_DATABASE}
    volumes:
      - ./pgdata:/var/lib/postresql/data
    ports:
      - ${TYPEORM_PORT}:${TYPEORM_PORT}
  backend:
    container_name: backend-AngularNestJS_Full-stack
    build:
      context: ./backend
    depends_on:
      - db
    restart: unless-stopped
    ports:
      - '${API_PORT}:3001'
    environment:
      - API_PORT=${API_PORT}
      - API_HOST=${API_HOST}
      - TYPEORM_CONNECTION=${TYPEORM_CONNECTION}
      - TYPEORM_USERNAME=${TYPEORM_USERNAME}
      - TYPEORM_PASSWORD=${TYPEORM_PASSWORD}
      - TYPEORM_DATABASE=${TYPEORM_DATABASE}
      - TYPEORM_PORT=${TYPEORM_PORT}
      - TYPEORM_HOST=db
  frontend:
    container_name: frontend-AngularNestJS_Full-stack
    build:
      context: ./frontend
    depends_on:
      - db
      - backend
    restart: unless-stopped
    ports:
      - '80:80'

УстанавливаСм TypeORM ΠΌΠΎΠ΄ΡƒΠ»ΡŒ:

cd backend/
yarn add @nestjs/typeorm typeorm postgres

ΠŸΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ΠΈΠΌ Π² Ρ„Π°ΠΉΠ» app.module.ts ΠΈ Ρ‡Π΅Ρ€Π΅Π· imports ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ TypeOrmModule:

TypeOrmModule.forRootAsync({
  imports: [ConfigModule],
  inject: [ConfigService],
  useFactory: async (config: ConfigService) => ({
    type: config.get<'postgres'>('TYPEORM_CONNECTION'),
    host: config.get<string>('TYPEORM_HOST'),
    username: config.get<string>('TYPEORM_USERNAME'),
    password: config.get<string>('TYPEORM_PASSWORD'),
    database: config.get<string>('TYPEORM_DATABASE'),
    port: config.get<number>('TYPEORM_PORT'),
    entities: [__dirname + 'dist/**/*.entity{.ts,.js}'],
    synchronize: true,
    autoLoadEntities: true,
    logging: true,
    dropSchema: true,
  }),
}),

Π‘Ρ‚Π°Ρ€Ρ‚ΡƒΠ΅ΠΌ Π² Ρ„ΠΎΠ½Π΅ Ρ„Π°ΠΉΠ» docker-compose.yml (процСсс Π΄ΠΎΠ»Π³ΠΈΠΉ):

cd ..
docker-compose up -d

Π‘ΠΌΠΎΡ‚Ρ€ΠΈΠΌ Π·Π°ΠΏΡƒΡ‰Π΅Π½Π½Ρ‹Π΅ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Ρ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ Π² случаС ΡƒΠ΄Π°Ρ‡Π½ΠΎΠ³ΠΎ запуска Ρ„Π°ΠΉΠ» docker-compose.yml:

cd ..
docker ps

Π’ случаС успСха Π² Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π»Π΅ ΡƒΠ²ΠΈΠ΄ΠΈΠΌ ΠΏΠΎ ΠΊΡ€Π°ΠΉΠ½Π΅ΠΉ ΠΌΠ΅Ρ€Π΅ ΠΎΠ΄ΠΈΠ½ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ Π·Π°ΠΏΡƒΡ‰Π΅Π½Π½Ρ‹ΠΉ Π½Π° ΠΏΠΎΡ€Ρ‚Ρƒ 5432

ЗапускаСм ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Ρ‡Ρ‚ΠΎΠ±Ρ‹ убСдится, Ρ‡Ρ‚ΠΎ Π±Π°Π·Π° Π΄Π°Π½Π½Ρ‹Ρ… ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΠ»Π°ΡΡŒ:

cd backend/
nest start --watch

Π’ случаС успСха Π² Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π»Π΅ ΡƒΠ²ΠΈΠ΄ΠΈΠΌ query: SELECT * FROM current_schema() ΠΈ Ρ‚.Π΄.

УстанавливаСм GraphQL (Ссли ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π·Π°ΠΏΡƒΡ‰Π΅Π½ΠΎ, Π² Π½Π°Ρ‡Π°Π»Π΅ Ρ‚ΠΎΡ€ΠΌΠΎΠ·ΠΈΠΌ Π΅Π³ΠΎ ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ Π² Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π»Π΅: Ctrl + C):

cd backend/
yarn add @nestjs/graphql @nestjs/apollo graphql apollo-server-express

ΠŸΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ΠΈΠΌ Π² Ρ„Π°ΠΉΠ» app.module.ts ΠΈ Ρ‡Π΅Ρ€Π΅Π· imports ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ GraphQLModule:

GraphQLModule.forRoot<ApolloDriverConfig>({
  driver: ApolloDriver,
  autoSchemaFile: 'schema.gql',
}),

Π”Π°Π»Π΅Π΅ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅ΠΌ ΠΌΠΎΠ΄ΡƒΠ»ΡŒ users (nest автоматичСски сгСнСрируСт Π² ΠΏΠ°ΠΏΠΊΠ΅ srs ΠΏΠ°ΠΏΠΊΡƒ users ΠΈ создаст Π² Π½Π΅ΠΉ Ρ„Π°ΠΉΠ» users.module.ts):

cd backend/
nest g mo users

Π‘ΠΎΠ·Π΄Π°Π΄Π°Ρ‘ΠΌ ΠΏΠ΅Ρ€Π²ΡƒΡŽ ΡΡƒΡ‰Π½ΠΎΡΡ‚ΡŒ: Π² ΠΏΠ°ΠΏΠΊΠ΅ users создаСм ΠΏΠ°ΠΏΠΊΡƒ entities Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ создаСм Ρ„Π°ΠΉΠ» user.entity.ts ΠΈ навСшиваСм Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€Ρ‹ @ TypeORM & GraphQL. Код ΠΈΠΌΠ΅Π΅Ρ‚ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ Π²ΠΈΠ΄:

import {
  Column,
  CreateDateColumn,
  Entity,
  PrimaryGeneratedColumn,
  UpdateDateColumn,
} from 'typeorm';
import { Field, Float, ID, ObjectType } from '@nestjs/graphql';

@ObjectType()
@Entity('users')
export class UserEntity {
  @Field(() => ID)
  @PrimaryGeneratedColumn()
  id: number | string;

  @Field()
  @CreateDateColumn()
  createdAt: Date;

  @Field()
  @UpdateDateColumn()
  updatedAt: Date;

  @Field()
  @Column()
  email: string;

  @Field({ nullable: true })
  @Column({ nullable: true })
  name: string;
}

ΠŸΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ΠΈΠΌ Π² Ρ„Π°ΠΉΠ» users.module.ts ΠΈ Π² ΠΈΠΌΠΏΠΎΡ€Ρ‚Π΅ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌ Π½Π°Π±ΠΎΡ€ ΠΎΠΏΡ†ΠΈΠΉ:

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UserService } from './services/user/user.service';
import { UserResolver } from './resolvers/user/user.resolver';
import { UserEntity } from 'src/users/entities/user.entity';

@Module({
  imports: [TypeOrmModule.forFeature([UserEntity])],
  providers: [UserService, UserResolver],
})
export class UsersModule {}

Π’ ΠΏΠ°ΠΏΠΊΠ΅ users создаСм сСрвис для манипулирования нашими ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡΠΌΠΈ:

cd backend/
nest g s users/services/user

Π’ ΠΏΠ°ΠΏΠΊΠ΅ users создаСм ΠΏΠ°ΠΏΠΊΡƒ resolver Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅ΠΌ Ρ„Π°ΠΉΠ» user.resolver.ts:

cd backend/
nest r s users/resolvers/user

user.resolver.ts: import { Test, TestingModule } from '@nestjs/testing'; import { UserResolver } from './user.resolver';

describe('UserResolver', () => {
  let resolver: UserResolver;

  beforeEach(async () => {
    const module: TestingModule = await Test.    createTestingModule({
      providers: [UserResolver],
    }).compile();

    resolver = module.get<UserResolver>(UserResolver);
  });

  it('should be defined', () => {
    expect(resolver).toBeDefined();
  });
});

Π’ ΠΏΠ°ΠΏΠΊΠ΅ users создаСм ΠΏΠ°ΠΏΠΊΡƒ inputs Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ создаСм Π΄Π²Π° Ρ„Π°ΠΉΠ»Π°:

  • create-user.input.ts

    import { Field, InputType } from '@nestjs/graphql';

    @InputType() export class CreateUserInput { @Field() email: string;

    @Field({ nullable: true })
    name: string;
    

    }

  • update-user.input.ts

    import { Field, ID, InputType } from '@nestjs/graphql';

    @InputType() export class UpdateUserInput { @Field(() => ID) id: number;

    @Field({ nullable: true })
    email: string;
    
    @Field({ nullable: true })
    name: string;
    

    }

ΠžΡ‚ΠΊΡ€Ρ‹Π²Π°Π΅ΠΌ Ρ„Π°ΠΉΠ» user.service.ts ΠΈ наполняСм Π΅Π³ΠΎ ΠΌΠ΅Ρ‚ΠΎΠ΄Π°ΠΌΠΈ:

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { UserEntity } from 'src/users/entities/user.entity';
import { CreateUserInput } from 'src/users/inputs/create-user.input';
import { UpdateUserInput } from 'src/users/inputs/update-user.input';
import { Repository } from 'typeorm';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(UserEntity)
    private readonly userRepository: Repository<UserEntity>,
  ) {}

  async createUser(createUserInput: CreateUserInput): Promise<UserEntity> {
    return await this.userRepository.save({ ...createUserInput });
  }

  async getOneUser(id: number): Promise<UserEntity> {
    return await this.userRepository.findOne({
      where: {
        id: id,
      },
    });
  }

  async getAllUsers(): Promise<UserEntity[]> {
    return await this.userRepository.find();
  }

  async removeUser(id: number): Promise<number> {
    await this.userRepository.delete({ id });
    return id;
  }

  async updateUser(updateUserInput: UpdateUserInput): Promise<UserEntity> {
    await this.userRepository.update(
      { id: updateUserInput.id },
      { ...updateUserInput },
    );
    return await this.getOneUser(updateUserInput.id);
  }
}

ΠŸΡ€ΠΎΠ±ΡƒΠ΅ΠΌ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒΡΡ:

cd backend/
docker ps    //провСряСм Ρ‡Ρ‚ΠΎ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ Π·Π°ΠΏΡƒΡ‰Π΅Π½ ΠΈΠ½Π°Ρ‡Π΅ docker-compose up -d
yarn start

Π’ случаС успСха Π² Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π»Π΅ ΡƒΠ²ΠΈΠ΄ΠΈΠΌ query: CREATE TABLE "users" & App started on port: 3001

ΠžΡ‚ΠΊΡ€Ρ‹Π²Π°Π΅ΠΌ Π² Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π΅ Π΄Π²Π΅ Π²ΠΊΠ»Π°Π΄ΠΊΠΈ с адрСсами:

Запуск нашСго ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Docker. Π‘ΠΎΠ·Π΄Π°Ρ‘ΠΌ Π² ΠΊΠΎΡ€Π½Π΅ прилоТСния Dockerfile со ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ ΠΊΠΎΠ΄ΠΎΠΌ:

FROM node:18-alpine AS builder
WORKDIR /app
COPY /*.json ./
COPY . .
RUN npm run build

FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app ./
EXPOSE 3001
CMD ["npm", "run", "start:prod"]

ДобавляСм Dockerfile Π² docker-compose.yml:

version: '3.8'

services:
  db:
    container_name: postgres-AngularNestJS_Full-stack
    image: postgres
    restart: always
    environment:
      - POSTGRES_USER=${TYPEORM_USERNAME}
      - POSTGRES_PASSWORD=${TYPEORM_PASSWORD}
      - POSTGRES_DB=${TYPEORM_DATABASE}
    volumes:
      - ./pgdata:/var/lib/postresql/data
    ports:
      - ${TYPEORM_PORT}:${TYPEORM_PORT}
  backend:
    container_name: backend-AngularNestJS_Full-stack
    build:
      context: ./backend
    depends_on:
      - db
    restart: unless-stopped
    ports:
      - '${API_PORT}:3001'
    environment:
      - API_PORT=${API_PORT}
      - API_HOST=${API_HOST}
      - TYPEORM_CONNECTION=${TYPEORM_CONNECTION}
      - TYPEORM_USERNAME=${TYPEORM_USERNAME}
      - TYPEORM_PASSWORD=${TYPEORM_PASSWORD}
      - TYPEORM_DATABASE=${TYPEORM_DATABASE}
      - TYPEORM_PORT=${TYPEORM_PORT}
      - TYPEORM_HOST=db
  frontend:
    container_name: frontend-AngularNestJS_Full-stack
    build:
      context: ./frontend
    depends_on:
      - db
      - backend
    restart: unless-stopped
    ports:
      - '80:80'

ЗапускаСм нашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Ρ‡Π΅Ρ€Π΅Π· ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ Docer (Ссли ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π·Π°ΠΏΡƒΡ‰Π΅Π½ΠΎ, Π² Π½Π°Ρ‡Π°Π»Π΅ Ρ‚ΠΎΡ€ΠΌΠΎΠ·ΠΈΠΌ Π΅Π³ΠΎ ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ Π² Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π»Π΅: Ctrl + C):

cd ..
docker-compose down
docker ps    //ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ наши ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Ρ‹
docker-compose up -d --build

Π‘ΠΎΠ·Π΄Π°Ρ‘ΠΌ frontend ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π½Π° Π±Π°Π·Π΅ Angular:

УстанавливаСм Angular Π½Π° ΠΊΠΎΠΌΠΏ:

npm install -g @angular/cli

ΠŸΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ΠΈΠΌ Π² Ρ€Π°Π½Π΅Π΅ ΡΠΎΠ·Π΄Π°Π½Π½ΡƒΡŽ ΠΏΠ°ΠΏΠΊΡƒ с нашим ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΎΠΌ, Π² ΠΌΠΎΡ‘ΠΌ случаС AngularNestJS_Full-stack для создания клиСнтской части прилоТСния (Π² Π΄Π°Π½Π½ΠΎΠΌ случаС это ΠΏΠ°ΠΏΠΊΠ° frontend):

cd ..
ng new frontend --package-manager=yarn --routing --skip-git --skip-tests --style=scss

ДобавляСм стили bootstrap, Ρ‡Ρ‚ΠΎ Π±Ρ‹ ΡΠΎΠΊΡ€Π°Ρ‚ΠΈΡ‚ΡŒ врСмя Π½Π° вСрстку:

cd ..
yarn add bootstrap

послС установки стилСй добавляСм ΠΈΡ… Π² Ρ„Π°ΠΉΠ» styles.scss:

@import "~bootstrap/dist/css/bootstrap.min.css";

Ρ‡Ρ‚ΠΎΠ±Ρ‹ всС Π±Ρ‹Π»ΠΎ Π² ΠΎΠ΄Π½ΠΎΠΌ стилС устанавливаСм ΠΈΠΊΠΎΠ½ΠΊΠΈ bootstrap:

yarn add bootstrap-icons

послС установки ΠΈΠΊΠΎΠ½ΠΎΠΊ добавляСм ΠΈΡ… Π² Ρ„Π°ΠΉΠ» styles.scss:

@import "~bootstrap-icons/font/bootstrap-icons.css";

Π² Ρ„Π°ΠΉΠ»Π΅ angular.json добавляСм строку: "changeDetection": "OnPush"

  "schematics": {
    "@schematics/angular:component": {
      "style": "scss",
      "skipTests": true,
      "changeDetection": "OnPush"
    },

ΠŸΡ€ΠΎΠ±ΡƒΠ΅ΠΌ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ Angular:

cd frontend/
ng serve --open

Π’ случаС успСха ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ откроСтся Π½Π° http://localhost:4200/

Π—Π°Ρ…ΠΎΠ΄ΠΈΠΌ Π² Ρ„Π°ΠΉΠ» app.component.html удаляСм всС Ρ‡Ρ‚ΠΎ Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΈ Π²Π·Π°ΠΌΠ΅Π½ пишСм свой ΠΊΠΎΠ΄:

<div class="container pt-3">
  <h1>Главная страница</h1>
  <router-outlet></router-outlet>
</div>

Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ Ρ„Π°ΠΉΠ» src/app/components/nav.component.ts

###########################################################################################

УстанавливаСм GraphQL (Ссли ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π·Π°ΠΏΡƒΡ‰Π΅Π½ΠΎ, Π² Π½Π°Ρ‡Π°Π»Π΅ Ρ‚ΠΎΡ€ΠΌΠΎΠ·ΠΈΠΌ Π΅Π³ΠΎ ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ Π² Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π»Π΅: Ctrl + C):

cd frontend/
ng add apollo-angular

? Url to your GraphQL API http://localhost:3001/graphql ? Version of GraphQL 16 Enter

ΠŸΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ΠΈΠΌ Π² ΠΏΠ°ΠΏΠΊΡƒ environments/ ΠΈ прописываСм Π² 2Ρ… Ρ„Π°ΠΉΠ»Π°Ρ… uri взятый Π² Ρ„Π°ΠΉΠ»Π΅ graphql.module.ts Π° Π½Π° Π΅Π³ΠΎ мСсто вписываСм ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ ΠΈΠ· environment.ts:

const uri = environment.graphql_uri;

environment.ts:

export const environment = {
  production: false,
  graphql_uri: 'http://localhost:3001/graphql',
};

environment.prod.ts:

export const environment = {
  production: true,
  graphql_uri: 'http://localhost:3001/graphql',
};