Nest.js, ReactJS, Typescript로 풀스택 개발

2024. 6. 7. 00:53서버 프로그래밍

오랜만에 Node.js로 풀스택 개발을 하게 되었는데, Nest.js를 백엔드로 ReactJS를 프론트엔드로 사용하기로 했다. 먼저 Nest.js 프로젝트를 생성한 다음, frontend라는 폴더를 만들고 거기에 ReactJS 프로젝트를 생성했다. 따라서, Nest.js 백엔드에서 빌드된 ReactJS의 파일을 보여주도록 app.module.ts를 수정했다.

https://docs.nestjs.com/first-steps

 

Documentation | NestJS - A progressive Node.js framework

Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Rea

docs.nestjs.com

 

app.module.ts

import { Module } from '@nestjs/common';
import { ServeStaticModule } from '@nestjs/serve-static';
import { join } from 'path';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { HealthController } from './health.controller';
import { ReadinessController } from './readiness.controller';

@Module({
  imports: [
    ServeStaticModule.forRoot({
      rootPath: join(__dirname, '..', 'frontend', 'build'),
      exclude: ['/api*'],
    }),
  ],
  controllers: [AppController, HealthController, ReadinessController],
  providers: [AppService],
})
export class AppModule {}

app.controller.ts

import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller('api')
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}

* app.module.ts에서 ServeStaticModule로 ReactJS의 build 폴더를 rootPath로 지정을 해도 계속 "Hello, World!"가 뜬다. app.controller.ts에서 AppController가 루트로 지정되어있기 때문이며 'api'로 변경해주자 해결되었다.

 

Implementing User Authentication in Nest.js
Securing Your Nest.js Application with Robust Authentication
User authentication is a critical component of server-side applications. Nest.js provides a straightforward way to implement authentication mechanisms, such as JWT (JSON Web Tokens), to secure your application.

// Example of a Nest.js authentication service using JWT
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class AuthService {
  constructor(private jwtService: JwtService) {}

  async validateUser(username: string, pass: string): Promise<any> {
    // Logic to validate the user credentials
  }

  async login(user: any) {
    const payload = { username: user.username, sub: user.userId };
    return {
      access_token: this.jwtService.sign(payload),
    };
  }
}


Managing Access Tokens and Environment Variables
Managing access tokens securely is essential for user authentication. Nest.js supports the use of environment variables, which can be stored in an .env file, to manage sensitive information such as secret keys for token generation.

// Using environment variables in Nest.js
import { config } from 'dotenv';
config();

// Accessing environment variables
const jwtSecret = process.env.JWT_SECRET;

 

https://www.dhiwise.com/post/mastering-server-side-rendering-with-nestjs-and-react

 

A Guide to Setting Up Nest.js with React

Learn how Nest.js and React are used to build apps.

www.dhiwise.com

https://bewar-usman.medium.com/running-react-js-with-nest-js-together-4ea2fa5b779d

 

Running React.js with Nest.js together

This blog post teaches you how to run nest.js and react.js together side by side. It offers a detailed walkthrough on how to run these two frameworks concurrently and combine them together under one…

bewar-usman.medium.com

 

* React 프로젝트를 Typescript로 생성하고자 할때

npx create-react-app my-app --template typescript

https://create-react-app.dev/docs/adding-typescript/ 

 

Adding TypeScript | Create React App

Note: this feature is available with react-scripts@2.1.0 and higher.

create-react-app.dev

 

Docker 설정 관련

https://www.tomray.dev/nestjs-docker-production

 

Ultimate Guide: NestJS Dockerfile For Production [2022]

Learn how to write a Dockerfile that creates a production optimized image using the NodeJS Alpine image and multistage builds.

www.tomray.dev

https://geshan.com.np/blog/2023/03/mongodb-docker-compose/

 

How to run MongoDB with Docker and Docker Compose a Step-by-Step guide

In this step-by-step tutorial learn how to run MongoDB with Docker and Docker Compose. Also has an example with Node.js + MongoDB with Docker Compose.

geshan.com.np

https://dev.to/chukwutosin_/step-by-step-guide-setting-up-a-nestjs-application-with-docker-and-postgresql-5hei

 

Step-by-Step Guide: Setting Up a NestJS Application with Docker and PostgreSQL

NestJS, PostgreSQL, and Docker are three powerful tools that can help you build robust web...

dev.to

 

Cypress 관련 (React Typescript)

https://docs.cypress.io/guides/component-testing/react/overview

 

React Component Testing | Cypress Documentation

Framework Support

docs.cypress.io

https://github.com/cypress-io/cypress-component-testing-apps/tree/main/react-cra5-ts

 

cypress-component-testing-apps/react-cra5-ts at main · cypress-io/cypress-component-testing-apps

Contribute to cypress-io/cypress-component-testing-apps development by creating an account on GitHub.

github.com

* 아래 레퍼런스들은 out date 되었거나 딱 맞지는 않지만 참고할만함

https://www.cypress.io/blog/2019/05/13/code-create-react-app-v3-and-its-cypress-tests-using-typescript

 

Writing Cypress tests in TypeScript using create-react-app v3

How to write end-to-end tests for a CRA v3 application with TypeScript.

www.cypress.io

https://www.freecodecamp.org/news/cypress-for-end-to-end-testing-react-apps/

 

How to Use Cypress for End-to-End Testing Your React Apps

React is a popular framework for building web applications. It's is one of the best options for frontend engineering because of its declarative approach to user interface design and component-based architecture. But it can be difficult to make sure your Re

www.freecodecamp.org

* GitLab 파이프라인에서 별도로 서버를 실행시키고, cypress로 e2e 테스트를 진행하고자 할때

Deploy backends as docker images in GitLab private registry

First you have to publish your docker images in the private registry of GitLab. You do this, because you now can reuse those images in another job. For this approach you need docker:dind. A simple example job to publish to a private registry on gitlab looks like:

before_script:
  - echo -n $CI_JOB_TOKEN | docker login -u gitlab-ci-token --password-stdin $CI_REGISTRY

publish:image:docker:
  stage: publish
  image: docker
  services:
    - name: docker:dind
      alias: docker
  variables:
    CI_DOCKER_NAME: ${CI_REGISTRY_IMAGE}/my-docker-image
  script:
    - docker pull $CI_REGISTRY_IMAGE || true
    - docker build --pull --cache-from $CI_REGISTRY_IMAGE --tag $CI_DOCKER_NAME --file Dockerfile .
    - docker push $CI_DOCKER_NAME
  only:
    - master

To see a real-world example, I have an example project that is public available.

Mimic your docker-compose.yml services in 1 job in the pipeline

Once you dockerized all backends and published the images on a private registry, you can start to mimic your docker-compose.yml with a GitLab job. A basic example:

test:e2e:
   image: ubuntu:20.04
   stage: test
   services:
      - name: postgres:12-alpine
        alias: postgress
      - name: mongo
        alias: mongo
      # my backend image
      - name: registry.gitlab.com/[MY_GROUP]/my-docker-image
        alias: server
   script:
      - curl http://server:3000 # expecting server exposes on port 3000, this should work
      - curl http://mongo:270117 # should work
      - curl http://postgress:5432 # should work!

Run the tests

Now everything is running in a single job in GitLab, you can simply start your front-end in detached mode and run cypress to test it. Example:

script:
   - npm run start & # start in detached mode
   - wait-on http://localhost:8080 # see: https://www.npmjs.com/package/wait-on
   - cypress run # make sure cypress is available as well

https://stackoverflow.com/questions/66071016/how-to-setup-gitlab-ci-e2e-tests-using-multiple-dockers

 

How to setup Gitlab CI E2E tests using Multiple dockers

I am a bit lost with the automated testing using Gitlab CI. I hope I can explain my problem so somebody can help me. I'll try to explain the situation first, after which I'll try to ask a question ...

stackoverflow.com

https://docs.gitlab.com/runner/executors/docker.html#create-a-network-for-each-job

 

Docker executor | GitLab

GitLab product documentation.

docs.gitlab.com

Connecting services

You can use inter-dependent services with complex jobs, like end-to-end tests where an external API needs to communicate with its own database.

For example, for an end-to-end test for a front-end application that uses an API, and where the API needs a database:

end-to-end-tests:
  image: node:latest
  services:
    - name: selenium/standalone-firefox:${FIREFOX_VERSION}
      alias: firefox
    - name: registry.gitlab.com/organization/private-api:latest
      alias: backend-api
    - postgres:14.3
  variables:
    FF_NETWORK_PER_BUILD: 1
    POSTGRES_PASSWORD: supersecretpassword
    BACKEND_POSTGRES_HOST: postgres
  script:
    - npm install
    - npm test

For this solution to work, you must use the networking mode that creates a new network for each job.

https://docs.gitlab.com/ee/ci/services/#connecting-services

 

Services | GitLab

GitLab product documentation.

docs.gitlab.com

 

* gitlab runner에서 cypress를 실행시키니 Xvfb가 없다며 에러가 뜬다. docker 이미지를 cypress 공식 이미지를 사용하는 것으로 해결했다.

Xvfb is an in-memory display server for a UNIX-like operating system, in your case Linux (Debian - 9.13). This is a system-level dependency that cypress assumes is installed beforehand. In the case of bitbucket env, this is not installed and hence this error. This is primarily used for Display (UI) in case of headed browsers while running cypress.

There are few easy workarounds here:

Installing the dependency manually: I won't suggest this as you might miss out few more dependencies unless you thoroughly look into all the dependencies.

Run headless browsers:: Headless browsers don't use Xvfb, so won't be facing this exact error but as I said in point 1, there can be other issues. Command will become cypress run --headless

Use Cypress provided Docker images (Suggested): I can see that you are using the node:14.15.4 image for this build. Instead of that, use a cypress provided official base images for whatever node version you want to run (Look for different node version in tags). If you look into the Dockerfile, you will see that they have taken an effort to install the dependencies needed to run Cypress inside the docker (You can see Xvfb there).

Also, look for already open issues when you get stuck in cypress-related issues, they have a very active and helpful issues section. I found this same issue in there: https://github.com/cypress-io/cypress/issues/14457

https://stackoverflow.com/questions/66373352/bitbucket-pipeline-your-system-is-missing-the-dependency-xvfb

 

Bitbucket pipeline Your system is missing the dependency: Xvfb

I'm trying to add cypress to the bitbucket pipeline but it tells me that I need to install Xvfb and I don't know how to keep going. This is my bitbucket.pipelines.yml # Template NodeJS build # T...

stackoverflow.com

 

* 프론트엔드가 백엔드의 하위 폴더에 있다보니 lint 설정에서 삽질을 해야하는 경우가 생겼다.

https://andrebnassis.medium.com/setting-eslint-on-a-react-typescript-project-2021-1190a43ffba

 

Setting ESLint on a React Typescript project 2021

A definitive guide to set ESLint on a React Typescript project

andrebnassis.medium.com

https://dev.to/quizzes4u/how-to-set-up-eslint-and-prettier-in-react-typescript-5-project-2023-hd6

 

How to set up ESLint and Prettier in React TypeScript 5 project? 2023

In this article, let's do step by step set up of ESLint and Prettier in React Typescript 5 project....

dev.to