[Nest] 01.初见nest.js

github => nest-starter

nest 介绍

Nest 是一个用于构建高效,可扩展的 Node.js 服务器端应用程序的框架。它使用渐进式 JavaScript,内置并完全支持 TypeScript(但仍然允许开发人员使用纯 JavaScript 编写代码)并结合了 OOP(面向对象编程),FP(函数式编程)和 FRP(函数式响应编程)的元素。

在底层,Nest 使用强大的 HTTP Server 框架,如 Express(默认)和 Fastify。Nest 在这些框架之上提供了一定程度的抽象,同时也将其 API 直接暴露给开发人员。这样可以轻松使用每个平台的无数第三方模块。

为什么用nest

近年来,感谢 Node.js,JavaScript 已成为前端和后端应用程序的网络“通用语言”。这产生了令人敬畏的项目,如 Angular,React 和 Vue,它们提高了开发人员的工作效率,并能够构建快速,可测试和可扩展的前端应用程序。然而,虽然 Node(和服务器端 JavaScript )存在大量优秀的库,帮助器和工具,但它们都没有有效地解决主要问题 - 架构。

Nest 提供了一个开箱即用的应用程序架构,允许开发人员和团队创建高度可测试,可扩展,松散耦合且易于维护的应用程序

环境搭建

您可以使用 Nest CLI 构建项目,也可以克隆启动项目(两者都会产生相同的结果)。

安装 cli

npm i -g @nestjs/cli

创建项目目录

nest new project-name

更简单些可以直接 clone 官方预设项目

git clone https://github.com/nestjs/typescript-starter.git project
cd project
npm install
npm run start

新创建的 project-name 目录结构

├── README.md
├── node_modules
├── nodemon-debug.json
├── nodemon.json
├── package-lock.json
├── package.json
├── src
├── test
├── tsconfig.json
├── tsconfig.spec.json
├── tslint.json
└── webpack.config.js

src 是源码目录

├── app.controller.ts # 根控制器
├── app.controller.spec.ts # 根控制器测试文件
├── app.module.ts # 应用程序根模块
├── app.service.ts # 根服务
└── main.ts # 应用程序入口文件

main.ts 代码

import { NestFactory } from '@nestjs/core';

async function bootstrap() {
  const app = await NestFactory.create();

  await app.listen(6688);
}
bootstrap();

通过 async 和 await 并使用了 NestFactory 核心类创建一个 Nest 应用实例.NestFactory 暴露了一些静态方法用于创建应用实例,create() 方法返回一个实现 INestApplication 接口的对象,.并且监听 6688 接口

开启应用

npm start

启动 HTTP 服务器,项目会启动并监听一个接口 6688,此时访问 localhost:6688 或者 127.0.0.1:6688 可以看到 nest 信息

Nest 可以在创建适配器后使用任何 Node HTTP 框架。 有两个支持开箱即用的 HTTP 平台:express 和 fastify。 您可以选择最适合您需求的产品。

express 和 fastify

当使用 express

npm i --save @nestjs/platform-express colors ip

main.ts

import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import { AppModule } from './app.module';
import { blue } from 'colors';
import { address } from 'ip';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);
  const port = 6333;
  await app.listen(port, () => {
    console.log(
      blue(
        `当前服务运行在 \n http://localhost:${port} \n http://${address()}:${port}`,
      ),
    );
  });
}
bootstrap();

当使用 fastify

npm i --save @nestjs/platform-fastify

main.ts

import { NestFactory } from '@nestjs/core';
import {
  FastifyAdapter,
  NestFastifyApplication,
} from '@nestjs/platform-fastify';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter(),
  );
  await app.listen(6688);
}
bootstrap();

不管是使用 express 还是 fastify,它都会暴露自己的应用程序界面.它们分别是 NestExpressApplication 和 NestFastifyApplication.将类型传递给 NestFactory.create() 方法时,就可以访问底层平台 API,app 对象可以调用 express 或者 fastify 的方法.当然该类型可以不指定.

快速创建模块

// 新建模块
nest g mo user

// 新建controller
nest g co user

// 新建service
nest g s user    

nest命令全称和简称

  • class (alias: cl)
  • controller (alias: co)
  • decorator (alias: d)
  • exception (alias: e)
  • filter (alias: f)
  • gateway (alias: ga)
  • guard (alias: gu)
  • interceptor (alias: i)
  • middleware (alias: mi)
  • module (alias: mo)
  • pipe (alias: pi)
  • provider (alias: pr)
  • service (alias: s)

cli 还有个好用的命令是nest info用来查询当前项目的情况

创建路由

修改user/user.controller.ts

import { Controller, Post, Body, Get } from '@nestjs/common';

@Controller('user')
export class UserController {
  @Get()
  public renderLoginPage(): string {
    return `<div style="color:blue">
        <form action="/collect/create" method="post">
            <div>
                <label for="name">Name:</label>
                <input name="name" type="text" id="name">
            </div>
            <div>
                <label for="mail">E-mail:</label>
                <input name="email" type="email" id="mail">
            </div>
            <div>
                <label for="msg">description:</label>
                <textarea name="description" id="description"></textarea>
            </div>
            <button type="submit">Send your message</button>
        </form>
    </div>`;
  }

  @Post('login')
  public login(
    @Body() loginInfo: { name: string; email: string; description: string },
  ): string {
    return `<div>${loginInfo.name} + ${loginInfo.email} + ${loginInfo.description}</div>`;
  }
}

重新执行start命令,然后在http://localhost:6333/user进行表单填写,然后就是进入login查看新息

Nest 请求装饰器

  • @Get()
  • @Post()
  • @Put()
  • @Delete()
  • @Patch()
  • @Options()
  • @Head()
  • @All()

HTTP 没有 All 方法,这是一个快捷方法用来接收任何类型的 HTTP 请求。

nodemon

nodemon用来监视node.js应用程序中的任何更改并自动重启服务,非常适合用在开发环境中。

npm install --save-dev nodemon

在nodemon.json中添加配置

{
  "watch": ["src"],
  "ext": "ts,tsx",
  "ignore": [
    "src/**/*.spec.ts",
    "dist/*",
    "docs/*",
    "node_modules/*",
    "public/*",
    "test/*",
    "static/*"
  ],
  "delay": "2500",
  "exec": "ts-node -r tsconfig-paths/register ./src/main.ts"
}

在package.json中scripts中添加

"dev": "export NODE_ENV=development && nodemon",

随便修改内容会发现服务会自动重启,适合用于开发模式

MVC设置视图

Nest 默认使用 Express 库,为了创建一个简单的 MVC(模型 - 视图 - 控制器)应用程序,我们必须安装一个模板引擎

npm install --save hbs

然后在main.ts文件中进行设置

  const app = await NestFactory.create<NestExpressApplication>(AppModule);

  // 设置public文件存放文件夹
  app.useStaticAssets(join(__dirname, '..', 'public'), {
    prefix: '/public/',
  });
  // 设置静态文件存放文件夹
  app.useStaticAssets(join(__dirname, '..', 'static'), {
    prefix: '/static/',
  });
  // 设置视图文件夹
  app.setBaseViewsDir(join(__dirname, '..', '/views'));
  // 设置视图引擎
  app.setViewEngine('hbs');
  // 设置视图部件的文件夹
  registerPartials(join(__dirname, '..', '/views/partials'));

新建hbs文件

hbs的基本使用

  • {{value}}, handlebars模板会自动匹配相应的数值,对象甚至是函数
    <h1>{{name}}</h1>
    <p>{{content}}</p>  
  • 分离html模块,小模板分离
// 直接引入login_view.hbs
{{> login_view}}
  • hbs的foreach循环
{{#each items}}
  {{label}}: {{@foo}}
{{/each}}
  • if判断
{{#if names.length}}
 <ul>
  {{#each names}}
   <li>{{this}}</li>
  {{/each}}
  </ul>
 {{/if}}

在views文件夹中新建login.hbs

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>login</title>
  </head>
  <body>
    {{ login }}
  </body>
</html>

同时修改user.controller.ts

import { Controller, Post, Get, Render } from '@nestjs/common';

@Controller('')
export class UserController {
  @Get('login')
  @Render('login.hbs')
  public login(): string {
    return '';
  }

  @Get('register')
  @Render('register.hbs')
  public register(): string {
    return '';
  }
}

添加webpack进行文件监听

npm i --save-dev webpack webpack-cli webpack-node-externals ts-loader

配置webpack

然后,我们需要在根目录创建一个webpack.config.js。

const webpack = require('webpack');
const path = require('path');
const nodeExternals = require('webpack-node-externals');

module.exports = {
  entry: ['webpack/hot/poll?100', './src/main.ts'],
  watch: true,
  target: 'node',
  externals: [
    nodeExternals({
      whitelist: ['webpack/hot/poll?100'],
    }),
  ],
  module: {
    rules: [
      {
        test: /.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      },
    ],
  },
  mode: 'development',
  resolve: {
    extensions: ['.tsx', '.ts', '.js'],
  },
  plugins: [new webpack.HotModuleReplacementPlugin()],
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'server.js',
  },
};

热模块更换

在main.ts中添加webpack的配置

declare const module: any;

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);
  addEngine(app);

  const port = 6333;
  await app.listen(port, () => {
    console.log(blue(`http server is start at ===> http://localhost:${port}`));
  });

  if (module.hot) {
    module.hot.accept();
    module.hot.dispose(() => app.close());
  }
}
bootstrap();

在package.json中添加

"webpack": "webpack --config webpack.config.js"

关闭node进程,重新执行dev和webpack命令

Doc

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容