发布于 2026-01-06 0 阅读
0

NestJS 和 NEXT.js 集成库简介

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

(注意,下面的博客系统正在建设中!哈哈)

GitHub 标志 saltyshiomix / nestpress

一个基于 NestJS 和 NEXT.js 的、可用于生产环境的个人博客系统

一个基于NestJSNEXT.js的、可用于生产环境的个人博客系统

路线图

  • 跨平台
  • 深色主题
  • 验证
  • 博客
  • 测试

用法

数据库设置

适用于 Mac 用户

#安装 PostgreSQL
$ brew install postgresql
#如果你想在启动时启动 PostgreSQL,请尝试这样做
$ brew services start postgresql
#创建用户“nestpressuser”,密码为“nestpresspass”
$ createuser -P nestpressuser
#创建数据库“nestpressdb”,所有者为“nestpressuser” 
$ createdb nestpressdb -O nestpressuser

适用于 Windows 用户

PostgreSQL
> postgresql-11.2-1-windows-x64.exe --install_runtimes 0
pgAdmin
  • 请访问https://www.pgadmin.org/download下载最新安装程序
  • 运行 pgAdmin 并以 root 用户身份登录
  • 右键单击Login/Group RolesCreate > Login/Group Role
    • General控制板
      • Namenestpressuser
    • Definition控制板:
      • Passwordnestpresspass
    • Priviledges控制板:
      • 全部Yes
  • 右键单击DatabasesCreate > Database
    • General标签页
      • Databasenestpressdb
      • Owner

核心库是@nestpress/next

本文将介绍@nestpress/next及其用途。

安装

$ npm install --save @nestpress/next

用法

首先,填充以下内容package.jsontsconfig.jsontsconfig.server.json

package.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

server/app.module.ts

在您的应用程序模块中注册NextModule,以便 Nest 可以处理依赖项:

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,
      });
  }
}

server/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);
  }
}

server/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();

pages/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 客户端

server/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);
  }
}

pages/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 应用,希望这对您有所帮助 :)

相关存储库

GitHub 标志 saltyshiomix / ark

基于 NestJS、TypeORM、NEXT.js(v9.3) 和 Material UI(v4) 的最简单身份验证系统。

基于NestJSTypeORMNEXT.js (v9)Material UI (v4)的最简单身份验证系统。

软件包许可证(MIT)

特征

技术

  • 热重载功能旨在提升开发者体验 :)
    • ts-node-dev - 编译您的 TypeScript 应用程序,并在文件修改后重新启动。
    • Next.js - React 框架
  • 数据库
  • ORM(对象关系映射)
    • TypeORM - 用于 TypeScript 和 JavaScript (ES7, ES6, ES5) 的 ORM
  • 服务器
    • NestJS——一个渐进式的Node.js框架,用于构建高效、可靠且可扩展的服务器端应用程序。
      • 内部使用Express——一个快速、无预设、极简的 Node.js Web 框架。
    • Next.js - React 框架
  • 环境变量
    • dotenv - 从 .env 加载环境变量…




文章来源:https://dev.to/saltyshiomix/an-introduction-of-the-integration-library-with-nestjs-and-next-js-29f1