DEV Community

Cover image for Trying out NestJS part 1: Setting up a dev environment for your React / NestJS applications that rocks
Arnaud Cortisse
Arnaud Cortisse

Posted on • Updated on

Trying out NestJS part 1: Setting up a dev environment for your React / NestJS applications that rocks

This article was originally published on my personal blog.

Introduction

In the context of my current job, I wanted to evaluate the various existing backend frameworks based on NodeJS. Why is that? The only Node.js backend framework I had ever used so far was express, which is an awesome light-weight framework, but that doesn't have any opinion whatsover on how you should structure your app.

During my investigation, I came across NestJS several times. The most appealing thing to me was its thorough documentation and its large ecosystem. I was especially interested in the OpenAPI integration, which I knew could greatly improve the frontend development experience when coupled with a code generator.
In the end, I decided to create a small POC to see whether it would be a fit.

Specifications of the project

Functional requirements

The POC is going to be a minimal, hideous "TODO list" app (styling is not in the scope of this endeavor).
In this POC, I'll be able to:

  • Add tasks,
  • Remove tasks,
  • List all tasks

Technical requirements

  • Use Typescript everywhere.
  • NestJS for the backend.
  • React for the frontend.
  • Tasks are saved in a Postgres DB.
  • Redis is used for caching responses.
  • API endpoints are documented using OpenAPI.
  • API endpoints' parameters are validated in the backend.
  • Frontend code related to the API endpoints is auto-generated.
  • The development environment is set up in docker.
  • Monorepo containing both the backend and the frontend.

Building the project

The source code for this part of the project is available here: https://github.com/arnaud-cortisse/trying-out-nestjs-part-1.

Setting up Docker dev environment

Since I took Docker and Kubernetes: The Complete Guide and Microservices with Node JS and React courses, I've been a huge fan of setting up my dev environment inside docker instances instead of setting it up directly on my machine. I love the fact that I can have everything up and running with a single command, without having to worry about dependency conflicts (is my current version of NPM compatible with that project?, etc.).

A few commands to execute

  • Install the Nest CLI: npm i -g @nestjs/cli (you might need to prefix it with sudo)
  • Create an empty folder: mkdir todo-list-app
  • Go inside the folder: cd todo-list-app
  • Init npm package: npm init -y
  • Init git, if you want to save your work: git init
  • Create frontend folder: mkdir -p packages/react-app
  • Create backend folder: mkdir -p packages/nestjs
  • Create the React app: npx create-react-app packages/react-app --template typescript
  • Create the NestJS app: nest new packages/nestjs
  • Delete the .git folder automatically created by NestJS: rm -rf packages/nestjs/.git
  • Create frontend env variables file: touch packages/react-app/.env.dev
  • Create backend env variables file: touch packages/nestjs/.env.dev
  • Create frontend Dockerfile for dev environment: touch packages/react-app/Dockerfile.dev
  • Create backend Dockerfile for dev environment: touch packages/nestjs/Dockerfile.dev
  • Create docker-compose file for dev environment: touch docker-compose.yml
  • Create frontend .dockerignore file: touch packages/react-app/.dockerignore
  • Create backend .dockerignore file: touch packages/nestjs/.dockerignore

A few files to fill / change

packages/react-app/Dockerfile.dev
FROM node:alpine
WORKDIR /app

COPY package.json .
RUN npm install --legacy-peer-deps
COPY . .

CMD ["npm", "run", "start"]
Enter fullscreen mode Exit fullscreen mode

--legacy-peer-deps is just a temporary fix for https://github.com/facebook/create-react-app/issues/9515.

packages/nestjs/Dockerfile.dev
FROM node:alpine

WORKDIR /app
RUN npm install -g @nestjs/cli
COPY package.json .
RUN npm install
COPY . .

CMD ["npm", "run", "start:dev"]
Enter fullscreen mode Exit fullscreen mode

Nothing crazy here, but we just make sure we install the NestJS CLI globally before doing anything else.

packages/react-app/.env.dev
REACT_APP_BACKEND_SCHEMA=http
REACT_APP_BACKEND_HOSTNAME=localhost
REACT_APP_BACKEND_PORT=3001
CHOKIDAR_USEPOLLING=true
Enter fullscreen mode Exit fullscreen mode

CHOKIDAR_USEPOLLING is required when developing inside a docker container and using create-react-app (https://github.com/facebook/create-react-app/issues/1049#issuecomment-261731734).
The other variables are defined so that we can communicate with the NestJS API.

packages/nestjs/.env.dev
NEST_PORT=3001
PGHOST=postgres
PGPORT=5432
PGUSER=postgres
PGPASSWORD=example
PGDATABASE=postgres
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=password
REDIS_TTL=10
Enter fullscreen mode Exit fullscreen mode

We define the port on which NestJS will run as well as the Postgres and Redis configs.

packages/react-app/.dockerignore
node_modules
Enter fullscreen mode Exit fullscreen mode

We don't want the local node_modules folder to be copied over the instance.

packages/nestjs/.dockerignore
node_modules
Enter fullscreen mode Exit fullscreen mode
docker-compose.yml
version: "3.5"

services:
  nestjs:
    build:
      context: ./packages/nestjs
      dockerfile: Dockerfile.dev
    env_file:
     - ./packages/nestjs/.env.dev
    ports:
      - 3001:3001
    volumes:
      - ./packages/nestjs/:/app
      - /app/node_modules

  react_app:
    build:
      context: ./packages/react-app
      dockerfile: Dockerfile.dev
    env_file:
     - ./packages/react-app/.env.dev
    ports:
      - 3000:3000
    volumes:
      - ./packages/react-app/:/app
      - /app/node_modules

  postgres:
    image: postgres:13.1
    environment:
      POSTGRES_PASSWORD: example
    ports:
     - 5432:5432

  redis:
    image: redis:6.2-rc1
    environment:
      REDIS_PASSWORD: password

  redis_commander:
    image: rediscommander/redis-commander:latest
    restart: always
    environment:
      - REDIS_HOSTS=local:redis:6379
    ports:
      - 8081:8081
    depends_on:
      - redis
Enter fullscreen mode Exit fullscreen mode
  • nestjs is our backend.
  • react_app is our frontend.
  • postgres is going to be used to store the tasks.
  • redis is going to be used by NestJS to cache responses.
  • redis_commander is just a tool that allows us to examine the Redis DB quickly.
  • volumes under react_app and nestjs is key to get auto-reload whenever you modify files inside your editor. The only annoying thing with this setup is that you'll need to rebuild your docker images whenever you add a new dependency inside your node_modules (see https://github.com/BretFisher/node-docker-good-defaults for fixes).
packages/nestjs/src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(process.env.NEST_PORT);
}
bootstrap();

Enter fullscreen mode Exit fullscreen mode

Modify the port the app is listening to using the process.env.NEST_POST environment variable (defined in packages/nestjs/.env.dev).

Test current setup

You should now be able to start your dev environment typing docker-compose up in the root directory.

You can then go to the following addresses:

  • localhost:3000 --> React app.
  • localhost:3001 --> NestJS app.
  • localhost:8081 --> Redis Commander (which should be connected to your Redis instance).

Final words

With the current state, I've a working dev environment inside dev containers. All I have to do to get started is docker-compose up (sometimes, I have to do a docker-compose up --build, depending on whether or not new npm packages have been installed).
Whenever I update any .ts files in my code editor, the apps are reloaded accordingly, making it a very pleasant dev experience for the task at hand: asserting whether or not NestJS is going to be a good fit for me by developing a POC.

Part 2 is available here.

Discussion (0)