NestJS 및 NEXT.js와 통합 라이브러리 소개

TLDR


server/app.controller.ts와 같은 컨트롤러에서 :

import {
  Controller,
  Get,
  Req,
  Res,
} from '@nestjs/common';
import { NextService } from '@nestpress/next';

@Controller()
export class AppController {
  constructor(
    private readonly next: NextService,
  ) {}

  @Get()
  public async showIndexPage(@Req() req, @Res() res) {
    ///////////////////////////////////////////
    //                                       //
    //  this will render `pages/index.tsx`!  //
    //                                       //
    ///////////////////////////////////////////
    await this.next.render('/index', req, res);
  }
}

왜요?



NestJS은 진보적인 Node.js 프레임워크이므로 handlebars과 같은 뷰 엔진을 결정해야 합니다.

나는 React를 사용하는 것을 좋아하고 때때로 블로그 시스템을 만들 때 더 나은 SEO 결과를 얻고 싶습니다.

이 경우 NEXT.js을 선택하는 것이 좋습니다.

그러나 NestJS 위에 NEXT.js를 어떻게 사용합니까?

NEXT.js는 SSR 라이브러리이므로 정적 html 파일을 생성하는 서버가 이미 포함되어 있습니다.

그리고 서버 데이터를 NEXT.js 클라이언트에 어떻게 동적으로 전달합니까?

왜 그리고 어떻게 나에게 다가오고 있는지, 그래서 나는 통합 라이브러리를 작성하기로 결정했습니다.

#showdev



(아래 블로깅 시스템이 공사 중이니 주의하세요! ㅋㅋ)


짭짤한 / 네스트프레스


NestJS 및 NEXT.js 위에 제작 준비가 된 개인 블로그 시스템








NestJSNEXT.js 위에 생산 준비가 된 개인 블로그 시스템

로드맵



크로스 플랫폼
어두운 테마
인증
블로깅
테스트

용법


데이터베이스 설정


Mac 사용자의 경우

# install postgresql
$ brew install postgresql
# if you want to start postgresql in startup, try do this
$ brew services start postgresql
# create user "nestpressuser" with password "nestpresspass"
$ createuser -P nestpressuser
# create database "nestpressdb" owened by "nestpressuser"
$ createdb nestpressdb -O nestpressuser

Windows 사용자의 경우

PostgreSQL
> postgresql-11.2-1-windows-x64.exe --install_runtimes 0
pgAdmin
  • Download a latest installer at https://www.pgadmin.org/download
  • Run the pgAdmin and login with a root user
  • Right click Login/Group Roles and Create > Login/Group Role
    • General Panel
      • Name: nestpressuser
    • Definition Panel:
      • Password: nestpresspass
    • Priviledges Panel:
      • Check all Yes
  • Right click Databases and Create > Database
    • General Tab
      • Database: nestpressdb
      • Owner

And the core library is @nestpress/next.

In this article, I will introduce @nestpress/next and its usage.

설치

$ npm install --save @nestpress/next

용법



먼저 package.json , tsconfig.jsontsconfig.server.json를 채웁니다.

패키지.json



{
  "name": "sample-app",
  "scripts": {
    "dev": "ts-node --project tsconfig.server.json server/main.ts",
    "build": "next build && tsc --project tsconfig.server.json",
    "start": "cross-env NODE_ENV=production node .next/production-server/main.js"
  },
  "dependencies": {
    "@nestjs/common": "latest",
    "@nestjs/core": "latest",
    "@nestpress/next": "latest",
    "next": "latest",
    "react": "latest",
    "react-dom": "latest",
    "reflect-metadata": "latest",
    "rxjs": "latest"
  },
  "devDependencies": {
    "@types/node": "latest",
    "@types/react": "latest",
    "@types/react-dom": "latest",
    "cross-env": "latest",
    "ts-node": "latest",
    "typescript": "latest"
  }
}

tsconfig.json



{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "moduleResolution": "node",
    "jsx": "preserve",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "strict": true,
    "noEmit": true,
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "isolatedModules": true,
    "resolveJsonModule": true,
    "forceConsistentCasingInFileNames": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "incremental": true
  },
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}

tsconfig.server.json



{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "module": "commonjs",
    "noEmit": false,
    "outDir": ".next/production-server"
  },
  "include": [
    "server"
  ]
}

둘째, 이 파일을 구현합니다.
  • NestJS 쪽
  • server/app.module.ts
  • server/app.controller.ts
  • server/main.ts

  • NEXT.js 쪽
  • pages/index.tsx


  • 서버/app.module.ts



    Nest가 종속성을 처리할 수 있도록 애플리케이션 모듈에 등록NextModule:

    import {
      Module,
      NestModule,
      MiddlewareConsumer,
      RequestMethod,
    } from '@nestjs/common';
    import {
      NextModule,
      NextMiddleware,
    } from '@nestpress/next';
    import { AppController } from './app.controller';
    
    @Module({
      imports: [
        // register NextModule
        NextModule,
      ],
      controllers: [
        AppController,
      ],
    })
    export class AppModule implements NestModule {
      configure(consumer: MiddlewareConsumer) {
        // handle scripts
        consumer
          .apply(NextMiddleware)
          .forRoutes({
            path: '_next*',
            method: RequestMethod.GET,
          });
    
        // handle other assets
        consumer
          .apply(NextMiddleware)
          .forRoutes({
            path: 'images/*',
            method: RequestMethod.GET,
          });
    
        consumer
          .apply(NextMiddleware)
          .forRoutes({
            path: 'favicon.ico',
            method: RequestMethod.GET,
          });
      }
    }
    

    서버/app.controller.ts



    다음과 같이 컨트롤러에서 NextService를 사용하십시오.

    import {
      IncomingMessage,
      ServerResponse,
    } from 'http';
    import {
      Controller,
      Get,
      Req,
      Res,
    } from '@nestjs/common';
    import { NextService } from '@nestpress/next';
    
    @Controller()
    export class AppController {
      constructor(
        private readonly next: NextService,
      ) {}
    
      @Get()
      public async showHome(@Req() req: IncomingMessage, @Res() res: ServerResponse) {
        // this will render `pages/index.tsx`!
        await this.next.render('/index', req, res);
      }
    }
    

    서버/main.ts



    기본 진입점에서 Next.js 서비스를 준비합니다.

    import { NestFactory } from '@nestjs/core';
    import { NextModule } from '@nestpress/next';
    import { AppModule } from './app.module';
    
    async function bootstrap() {
      const app = await NestFactory.create(AppModule);
    
      app.get(NextModule).prepare().then(() => {
        app.listen(3000, 'localhost', () => {
          console.log('> Ready on http://localhost:3000 with Next.js!');
        });
      });
    }
    
    bootstrap();
    

    페이지/index.tsx


    pages 디렉토리에서 Next.js 방식과 동일하게 수행할 수 있습니다.

    export default () => (
      <p>Next.js on top of NestJS!</p>
    );
    

    개발 모드



    $ yarn dev (or `npm run dev`)
    
    http://localhost:3000로 이동하면 Next.js on top of NestJS!가 표시됩니다.

    생산 모드



    $ yarn build (or `npm run build`)
    $ yarn start (or `npm start`)
    

    옵션



    import { NestFactory } from '@nestjs/core';
    import { NextModule } from '@nestpress/next';
    import { AppModule } from './app.module';
    
    async function bootstrap() {
      const app = await NestFactory.create(AppModule);
    
      app.get(NextModule).prepare({
        /**
         * Whether to launch Next.js in dev mode
         */
        dev: process.env.NODE_ENV !== 'production',
        /**
         * Where the Next project is located
         */
        dir: process.cwd(),
        /**
         * Hide error messages containing server information
         */
        quiet: false,
        /**
         * Object what you would use in next.config.js
         */
        conf: {},
      }).then(() => {
        app.listen(3000, 'localhost', () => {
          console.log('> Ready on http://localhost:3000 with Next.js!');
        });
      });
    }
    
    bootstrap();
    

    고급 사용: 서버 데이터를 NEXT.js 클라이언트에 전달


    서버/app.controller.ts



    @Controller()
    export class AppController {
      constructor(
        private readonly next: NextService,
        private readonly articleService: ArticleService,
      ) {}
    
      @Get()
      public async showHome(@Req() req: IncomingMessage, @Res() res: ServerResponse) {
        const articles = await this.articleService.findAll();
        const data = { articles };
        await this.next.render('/index', data, req, res);
      }
    }
    

    페이지/index.tsx



    import fetch from 'isomorphic-unfetch';
    
    const HomePage = (props) => {
      const { articles } = props;
    
      return (
        <ul>
          {articles.map((article, index) => (
            <li key={index}>{article.title}</li>
          ))}
        </ul>
      );
    };
    
    // we must define `getInitialProps` so that the NEXT.js can generate static markups
    HomePage.getInitialProps = async ({ req, query }) => {
      const isServer: boolean = !!req;
    
      let articles;
      if (isServer) {
        // in the NEXT.js server side, we can pass the server data
        // this `query.articles` is passed from AppController
        articles = query.articles;
      } else {
        // in the NEXT.js client side, we need to fetch the same data above
        const response = await fetch('http://localhost:3000/api/articles');
        articles = await response.json();
      }
    
      return {
        articles,
      };
    };
    
    export default HomePage;
    

    결론



    NestJS와 NEXT.js의 통합은 약간 까다롭지만 SSR로 React 앱을 호스팅해야 하는 경우 도움이 되었으면 합니다. :)

    관련 저장소




    짭짤한 / 방주


    NestJS, TypeORM, NEXT.js(v9.3) 및 Material UI(v4) 위에 가장 쉬운 인증 시스템입니다.






    NestJS , TypeORM , NEXT.js (v9)Material UI (v4) 위에 가장 쉬운 인증 시스템입니다.



    특징


  • 교차 플랫폼 - Mac, Linux 및 Windows
  • 엔티티와 데이터베이스 동기화 - TypeORM에서 제공
  • 서버 측 렌더링 - NEXT.js 제공
  • API 서버 - NestJS에 의해 구동
  • 인증 - Passport에서 제공

  • Material UI 디자인

  • 기술


  • 개발자 경험을 위한 핫 리로딩 :)

  • ts-node-dev - 파일이 수정되면 TS 앱을 컴파일하고 다시 시작함

  • NEXT.js - 반응 프레임워크



  • TypeScript - 확장되는 자바스크립트

  • 데이터베이스

  • PostgreSQL - 세계에서 가장 진보된 오픈 소스 관계형 데이터베이스

  • ORM(개체 관계형 매핑)

  • TypeORM - TypeScript 및 JavaScript용 ORM(ES7, ES6, ES5)

  • 서버

  • NestJS - 효율적이고 안정적이며 확장 가능한 서버 측 응용 프로그램을 구축하기 위한 진보적인 Node.js 프레임워크
  • 내부적으로 사용Express - Node.js를 위한 빠르고 독선적이지 않은 미니멀리스트 웹 프레임워크


  • NEXT.js - 반응 프레임워크

  • 환경 변수

  • dotenv - .env…에서 환경 변수를 로드합니다.




  • View on GitHub

    좋은 웹페이지 즐겨찾기