NextJS 와 NestJS를 같이 써보자 (1)

pudding·2023년 3월 12일
15
post-thumbnail

포스트하기 앞서 짧게 두 프레임워크를 연동하려 하는 이유를 말하자면, 우선 개인 포트폴리오 웹 페이지를 만들고 싶었다. 그래서 무료 클라우드 서버를 찾는 와중 국내 서비스인 클라우드타입 을 알게 되었다. 다른 해외 서비스는 해외에 서버가 있기 때문에 느린데 이 녀석은 정말 빠르다. 이러한 이유 때문에 클라우드타입으로 정했는데 서비스 4개 까지만 무료라서 서비스 절약 차원에 백엔드 서버 따로 프론트엔드 서버 따로 서비스를 구성하기 싫었다. 그래서 백엔드, 프론트엔드 한번에 배포하는 쪽으로 방향을 잡았다. 프론트엔드는 프레임워크/라이브러리 삼대장이라고 불리는 Angular, Vue, React 다 경험해봤지만 이제 React 로 방향을 잡은 것 같고 백엔드로는 Java를 주로 써왔지만 NodeJS는 개인적으로 공부중이다.
그래서 결론은 React 프레임워크 NextJS 와 공부를 목적으로 NodeJS 프레임워크인 NestJS를 연동하고 (보통 custom server로 express 연동을 하던데.. 난 nest 쓰고 싶어) 클라우드타입에 배포까지 해보는 과정을 기록하려고 한다.

🎉 1. create-next-app

create-next-app 으로 간단히 NextJS 어플리케이션을 만들어준다. 나는 기본 설정으로 해줬다.

npx create-next-app

√ What is your project named? ... next-with-nest
√ Would you like to use TypeScript with this project? ... No / *Yes
√ Would you like to use ESLint with this project? ... No / *Yes
√ Would you like to use `src/` directory with this project? ... *No / Yes
√ Would you like to use experimental `app/` directory with this project? ... *No / Yes
√ What import alias would you like configured? ... @/*

🎉 2. NestJS 설치

cd next-with-nest
npm install @nestjs/common @nestjs/core @nestjs/platform-express

🎉 3. tsconfig.json 수정

해당 옵션 추가

{
  "compilerOptions": {
    ...,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "strictPropertyInitialization": false,
  }
}

안하면 타입스크립트 에러난다.

🎉 4. server 폴더 생성

NestJS 용 서버 디렉토리를 생성한다. 이름은 맘대로.

mkdir server

🎉 5. module, controller, service 파일 생성

@nestjs/cli 로 프로젝트를 생성하면 기본으로 생성되는 파일이다. 우리는 @nestjs/cli 로 생성을 안했기 때문에 nest g 를 쓰든 해서 직접 만들어주자. 아 물론 server 디렉토리에.


📄 server/app.service.ts

import { Injectable } from "@nestjs/common";

@Injectable()
export class AppService {
  getHello(): string {
    return "Hello World!";
  }
}

📄 server/app.controller.ts

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

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

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

📄 server/app.module.ts

import { Module } from "@nestjs/common";
import { AppController } from "./app.controller";
import { AppService } from "./app.service";

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

그리고 controller를 만들어 줬으니 create-next-app 을 이용하면 자동으로 생성되어 있는 pages/api/hello.ts 파일은 삭제한다.

🎉 6. NextJS 와 NestJS 연결

서로 연결하기 위해 파일 세개를 추가로 생성하자. 아래 코드는 api/~~ 로 들어오는 모든 요청을 catchAll 에서 받아 NestApplication 과 연결하고 /api 로 들어오는 요청은 catchAll 이 받지 못하기 때문에 index.ts 파일을 추가하여 catchAll 을 export 하는 내용이다.


📄 server/main.ts

import { NestFactory } from "@nestjs/core";
import { AppModule } from "@/server/app.module";
import * as http from "http";
import { NextApiHandler } from "next";
import { INestApplication } from "@nestjs/common";

export module Main {
  let app: INestApplication;

  export async function getApp() {
    if (!app) {
      app = await NestFactory.create(AppModule, { bodyParser: false });
      app.setGlobalPrefix("api");
      await app.init();
    }

    return app;
  }

  export async function getListener() {
    const app = await getApp();
    const server: http.Server = app.getHttpServer();
    const [listener] = server.listeners("request") as NextApiHandler[];

    return listener;
  }
}

📄 pages/api/[...catchAll].ts

import { Main } from "@/server/main";
import { NextApiRequest, NextApiResponse } from "next";

const catchAll = (req: NextApiRequest, res: NextApiResponse) =>
  new Promise(async (resolve) => {
    const listener = await Main.getListener();
    listener(req, res);
    res.on("finish", resolve);
  });

export default catchAll;

📄 pages/api/index.ts

export { default } from "./[...catchAll]";

🎉 7. 결과 (디렉토리 구조)

이대로만 했다면 결과는 다음처럼 나올 것이다.

🎉 8. 확인

next 기본 페이지 잘나오고

api는?

잘나온다. 연동이 잘 된듯 하다.

🎊 마치며

소스가 간단해서 자세한 설명은 안했습니다.
다음 포스트에는 docker-compose 작성하고 컨테이너 올린 뒤 prisma 이용해서 DB 연결까지 하려고 합니다.
소스는 단계별로 github에 올릴 예정이니 태클 및 조언은 정말 감사히 받겠습니다.

📁 https://github.com/wlstn4115/next-with-nest

profile
I don't wanna be one of them.

4개의 댓글

comment-user-thumbnail
2023년 5월 15일

잘 읽었습니다~ nextjs에 이미 api 서버 기능이 있는데 nest를 백엔드로 따로 구성하신 이유가 있을까요?

1개의 답글
comment-user-thumbnail
2024년 1월 7일

이거 Next app 라우팅 방식으로는 혹시 예제 만들어주실 수 있으실까요?

답글 달기