npm install ts-node
.vscode\launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug ts",
"type": "node",
"request": "launch",
"runtimeArgs": [
"-r",
"ts-node/register"
], //核心
"args": [
"${relativeFile}"
]
}
]
}
$ npm i --save @nestjs/core @nestjs/common rxjs reflect-metadata @nestjs/platform-express
$ npm install -g ts-node
| 包名 | 介绍 |
|---|---|
| @nestjs/core | NestJS 框架的核心模块,提供构建、启动和管理 NestJS 应用程序的基础设施。 |
| @nestjs/common | 包含构建 NestJS 应用的基础设施和常用装饰器、工具类、接口等,用于定义控制器、服务、中间件、守卫、拦截器、管道、异常过滤器等。 |
| rxjs | 用于构建异步和事件驱动程序的库,基于可观察序列的概念,提供强大的功能来处理异步数据流。 |
| reflect-metadata | 在 JavaScript 和 TypeScript 中实现元编程的库,通过提供元数据反射 API,允许在运行时检查和操作对象的元数据。 |
| @nestjs/platform-express | NestJS 的平台适配器,用于将 NestJS 应用与 Express.js 集成,提供 Express.js 的中间件、路由等功能,并享受 NestJS 的模块化、依赖注入等高级特性。 |
| ts-node | 是一个用于直接执行 TypeScript 代码的 Node.js 实现,它允许开发者在不预先编译的情况下运行 TypeScript 文件 |
src\main.ts
// 从 @nestjs/core 模块中导入 NestFactory,用于创建 Nest 应用实例
import { NestFactory } from '@nestjs/core';
// 导入应用的根模块 AppModule
import { AppModule } from './app.module';
// 定义一个异步函数 bootstrap,用于启动应用
async function bootstrap() {
// 使用 NestFactory.create 方法创建一个 Nest 应用实例,并传入根模块 AppModule
const app = await NestFactory.create(AppModule);
// 让应用监听 3000 端口
await app.listen(3000);
}
// 调用 bootstrap 函数,启动应用
bootstrap();
NestFactory 是 NestJS 框架中用于创建 Nest 应用实例的核心类。它提供了一组静态方法,用于引导和启动应用程序。
NestFactory.create创建一个 Nest 应用实例,默认使用 Express 作为底层 HTTP 服务器。
src\app.module.ts
// 从 '@nestjs/common' 模块中导入 Module 装饰器
import { Module } from '@nestjs/common';
// 从当前目录导入 AppController 控制器
import { AppController } from './app.controller';
// 使用 @Module 装饰器定义一个模块
@Module({
// 在 controllers 属性中指定当前模块包含的控制器
controllers: [AppController],
})
// 定义并导出 AppModule 模块
export class AppModule {}
@Module 是 NestJS 框架中的一个装饰器,用于定义模块。模块是组织代码的基本单元,它们将相关的组件(如控制器、服务、提供者等)组合在一起。NestJS 的模块系统受到了 Angular 的启发,旨在促进代码的模块化和可维护性。
src\app.controller.ts
// 导入 Controller 和 Get 装饰器
import { Controller, Get } from '@nestjs/common';
// 使用 @Controller 装饰器标记类为控制器
@Controller()
export class AppController {
// 构造函数,目前没有任何参数和逻辑
constructor() {}
// 使用 @Get 装饰器标记方法为处理 GET 请求的路由
@Get()
// 定义 getHello 方法,返回类型为字符串
getHello(): string {
// 返回字符串 'hello'
return 'hello';
}
}
@Controller 是 NestJS 框架中的一个装饰器,用于定义控制器。控制器是处理传入 HTTP 请求的核心组件。每个控制器负责处理特定的请求路径和相应的 HTTP 方法。控制器使用路由装饰器(如 @Get、@Post 等)来定义路由和请求处理方法。
@Get 是 NestJS 框架中的一个装饰器,用于将控制器方法映射到 HTTP GET 请求。这个装饰器是由 @nestjs/common 模块提供的。通过使用 @Get 装饰器,可以指定该方法处理特定路径上的 GET 请求。
package.json
{
"name": "2.first-step",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "ts-node src/main.ts"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@nestjs/common": "^10.3.9",
"@nestjs/core": "^10.3.9",
"@nestjs/platform-express": "^10.3.9",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1"
}
}
tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"declaration": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"target": "ES2021",
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"incremental": true,
"skipLibCheck": true,
"strictNullChecks": false,
"noImplicitAny": false,
"strictBindCallApply": false,
"forceConsistentCasingInFileNames": false,
"noFallthroughCasesInSwitch": false,
}
}
| 选项名 | 选项介绍 |
|---|---|
module |
指定生成的模块代码的模块系统,commonjs 是 Node.js 的模块系统。 |
declaration |
生成 .d.ts 声明文件。 |
removeComments |
删除编译后的注释。 |
emitDecoratorMetadata |
为装饰器生成元数据。 |
experimentalDecorators |
启用实验性的装饰器特性。 |
esModuleInterop |
允许从没有默认导出的模块中默认导入。这对于兼容性模块非常有用。 |
target |
指定 ECMAScript 目标版本,ES2021 是一种现代的 JavaScript 版本。 |
sourceMap |
生成对应的 .map 文件。 |
outDir |
指定编译输出目录为 ./dist。 |
baseUrl |
设置解析非相对模块名的基准目录为 ./。 |
incremental |
启用增量编译,提升编译速度。 |
skipLibCheck |
跳过对所有声明文件的类型检查。 |
strictNullChecks |
启用严格的空值检查。 |
noImplicitAny |
禁止隐式 any 类型。 |
strictBindCallApply |
启用严格的 bind、call 和 apply 方法检查。 |
forceConsistentCasingInFileNames |
强制文件名大小写一致。 |
noFallthroughCasesInSwitch |
禁止 switch 语句中的 case 语句贯穿(fall through)。 |
ts-node 是一个用于直接执行 TypeScript 代码的 Node.js 实现,它允许开发者在不预先编译的情况下运行 TypeScript 文件。ts-node 结合了 TypeScript 编译器和 Node.js,使得开发和测试 TypeScript 代码更加便捷。
核心功能
即时编译和执行:
ts-node 在运行时即时编译 TypeScript 代码,并将其传递给 Node.js 以执行。这避免了需要先手动编译 TypeScript 代码为 JavaScript 的步骤。REPL 环境:
集成 TypeScript 配置:
ts-node 可以读取和使用项目中的 tsconfig.json 配置文件,以确保代码按照指定的 TypeScript 编译选项执行。安装
可以通过 npm 安装 ts-node:
npm install -g ts-node
或者在项目中本地安装:
npm install --save-dev ts-node
基本用法
ts-node src/index.ts
这条命令会即时编译并运行 src/index.ts 文件中的 TypeScript 代码。
ts-node
进入 REPL 环境后,可以直接输入和执行 TypeScript 代码。
tsconfig.json:如果需要使用特定的 tsconfig.json 配置文件,可以使用 --project 选项:
ts-node --project tsconfig.json src/index.ts
配置示例
tsconfig.json 是 TypeScript 的配置文件,ts-node 会读取并应用其中的配置。例如:
{
"compilerOptions": {
"module": "commonjs",
"target": "ES2020",
"strict": true,
"esModuleInterop": true
}
}
在上述配置中,TypeScript 编译器会将代码编译为 ES2020 标准的 JavaScript,并启用严格模式。
配合其他工具
在开发过程中,可以结合 nodemon 使用 ts-node,以便在代码更改时自动重启应用:
nodemon --exec ts-node src/index.ts
许多测试框架(如 Mocha、Jest)都支持与 ts-node 集成,以便直接编写和运行 TypeScript 测试代码。
使用 Mocha:
mocha --require ts-node/register src/**/*.spec.ts
使用 Jest:
在 jest.config.js 中配置:
module.exports = {
transform: {
'^.+\\.ts$': 'ts-jest'
},
testEnvironment: 'node',
moduleFileExtensions: ['ts', 'js']
};
性能优化
在大型项目中,运行 TypeScript 代码的性能可能会受到影响。可以使用一些选项来优化 ts-node 的性能:
跳过类型检查:
使用 --transpile-only 选项跳过类型检查,只进行转译:
ts-node --transpile-only src/index.ts
启用缓存:
使用 --cache 选项启用编译结果的缓存,以加快后续运行速度:
ts-node --cache src/index.ts
使用 swc 编译器:
swc 是一个速度非常快的 TypeScript/JavaScript 编译器,可以与 ts-node 配合使用:
首先安装 ts-node 和 @swc/core:
npm install ts-node @swc/core @swc/helpers
然后使用 ts-node 时指定 swc 作为编译器:
ts-node --swc src/index.ts
总结
ts-node 是一个强大的工具,使开发者能够在 Node.js 环境中直接运行 TypeScript 代码,而无需预先编译。它简化了开发流程,提高了开发效率,特别适合于快速开发和测试 TypeScript 应用程序。通过结合其他工具(如 nodemon 和测试框架),ts-node 能够在开发工作流中发挥更大的作用。
@nestjs/core 是 NestJS 框架的核心模块,提供了构建、启动和管理 NestJS 应用程序的基础设施。它包含了一些关键的类、接口和功能,用于处理依赖注入、模块管理、生命周期管理等。下面将详细讲解 @nestjs/core 的主要组成部分和它们的功能。
主要功能和组成部分
NestFactory:
create 和 createMicroservice,用于分别创建标准的 HTTP 应用和微服务应用。create(AppModule): 创建一个 HTTP 应用程序实例。createMicroservice(AppModule, options): 创建一个微服务实例。INestApplication:
listen(port, callback): 启动应用并监听指定端口。getHttpServer(): 获取底层的 HTTP 服务器实例。close(): 关闭应用。ModuleRef:
get<T>(type: Type<T> | string | symbol, options?: { strict: boolean }): T: 获取指定类型或标识符的提供者实例。resolve<T>(type: Type<T> | string | symbol, options?: { strict: boolean }): Promise<T>: 异步获取指定类型或标识符的提供者实例。Reflector:
get<T, K>(metadataKey: K, target: Type<any> | Function): T: 获取指定元数据键的值。getAll<T>(metadataKey: any): T[]: 获取所有元数据键的值。生命周期钩子:
OnModuleInit: 实现 onModuleInit 方法,在模块初始化时执行。OnModuleDestroy: 实现 onModuleDestroy 方法,在模块销毁时执行。OnApplicationBootstrap: 实现 onApplicationBootstrap 方法,在应用程序启动完成时执行。OnApplicationShutdown: 实现 onApplicationShutdown 方法,在应用程序关闭时执行。代码示例
以下是一个使用 @nestjs/core 构建和启动 NestJS 应用程序的示例:
import { NestFactory } from '@nestjs/core';
import { Module, Injectable, Controller, Get } from '@nestjs/common';
// 服务
@Injectable()
class AppService {
getHello(): string {
return 'Hello World!';
}
}
// 控制器
@Controller()
class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}
// 模块
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
class AppModule {}
// 创建和启动应用
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
console.log('Application is running on: http://localhost:3000');
}
bootstrap();
详解
服务 (AppService):
@Injectable 装饰器标记 AppService 类为可注入服务。getHello 方法返回字符串 "Hello World!"。控制器 (AppController):
@Controller 装饰器标记 AppController 类为控制器。@Get 装饰器标记 getHello 方法为处理 GET 请求的路由。模块 (AppModule):
@Module 装饰器配置模块的控制器和提供者。应用启动 (bootstrap):
NestFactory.create 方法创建应用实例。app.listen 启动应用监听 3000 端口,并输出应用运行信息。通过 @nestjs/core 提供的这些功能,开发者可以构建、配置和管理 NestJS 应用程序的各个方面,从而实现高效、可扩展的应用开发。
@nestjs/common 是 NestJS 框架的核心模块之一,包含了构建 NestJS 应用程序的基础设施和常用装饰器、工具类、接口等。它提供了一些常用的功能,用于定义控制器、服务、中间件、守卫、拦截器、管道、异常过滤器等。
主要功能
控制器 (Controllers):
@Get、@Post、@Put、@Delete 等,用于标记控制器方法对应的 HTTP 请求方法和路由。提供者 (Providers):
中间件 (Middleware):
use 方法来处理请求。守卫 (Guards):
canActivate 方法来决定请求是否可以继续处理。拦截器 (Interceptors):
intercept 方法来处理请求和响应。管道 (Pipes):
transform 方法来转换和验证请求数据。异常过滤器 (Exception Filters):
catch 方法来处理异常。元数据与反射 (Metadata & Reflection):
常用装饰器和工具类
代码示例
以下是一个使用 @nestjs/common 构建的简单 NestJS 应用示例:
import { Module, Injectable, Controller, Get, NestMiddleware, MiddlewareConsumer, NestModule } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
// 服务
@Injectable()
class AppService {
getHello(): string {
return 'Hello World!';
}
}
// 控制器
@Controller()
class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}
// 中间件
class LoggerMiddleware implements NestMiddleware {
use(req: any, res: any, next: () => void) {
console.log('Request...');
next();
}
}
// 模块
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(LoggerMiddleware).forRoutes(AppController);
}
}
// 创建和启动应用
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
console.log('Application is running on: http://localhost:3000');
}
bootstrap();
详解
服务 (AppService):
@Injectable 装饰器标记 AppService 类为可注入服务。getHello 方法返回字符串 "Hello World!"。控制器 (AppController):
@Controller 装饰器标记 AppController 类为控制器。@Get 装饰器标记 getHello 方法为处理 GET 请求的路由。中间件 (LoggerMiddleware):
NestMiddleware 接口的 use 方法,在每个请求前输出日志信息。模块 (AppModule):
@Module 装饰器配置模块的控制器和提供者。NestModule 接口的 configure 方法,配置 LoggerMiddleware 中间件。应用启动 (bootstrap):
NestFactory.create 方法创建应用实例。app.listen 启动应用监听 3000 端口,并输出应用运行信息。通过 @nestjs/common 提供的这些功能,开发者可以快速构建、配置和管理 NestJS 应用程序,提高开发效率,简化代码结构。
RxJS(Reactive Extensions for JavaScript)是一个用于构建异步和事件驱动程序的库,基于可观察序列的概念。RxJS 提供了强大的功能来处理异步数据流,使得编写复杂的异步操作变得更加简单和高效。
核心概念
Observable (可观察对象):
示例:
import { Observable } from 'rxjs';
const observable = new Observable(subscriber => {
subscriber.next('Hello');
subscriber.next('World');
subscriber.complete();
});
observable.subscribe(value => console.log(value));
Observer (观察者):
next、error 和 complete 三个方法。示例:
const observer = {
next: value => console.log(value),
error: err => console.error(err),
complete: () => console.log('Completed')
};
observable.subscribe(observer);
Subscription (订阅):
unsubscribe 方法取消订阅。const subscription = observable.subscribe(observer);
subscription.unsubscribe();
Operators (操作符):
map、filter、merge、concat、switchMap 等。示例:
import { from } from 'rxjs';
import { map, filter } from 'rxjs/operators';
const numbers = from([1, 2, 3, 4, 5]);
const squareOdd = numbers.pipe(
filter(n => n % 2 !== 0),
map(n => n * n)
);
squareOdd.subscribe(value => console.log(value));
Subject (主题):
示例:
import { Subject } from 'rxjs';
const subject = new Subject();
subject.subscribe(value => console.log(`Observer A: ${value}`));
subject.subscribe(value => console.log(`Observer B: ${value}`));
subject.next('Hello');
subject.next('World');
常用操作符
创建操作符:
of: 创建一个发出指定值的 Observable。from: 从数组、Promise、迭代器或 Observable-like 对象创建 Observable。interval: 创建一个发出递增数字的 Observable,使用定时器。转换操作符:
map: 将 Observable 发出的每个值应用一个函数,返回新的值。switchMap: 映射每个值为一个新的 Observable,并取消前一个内部 Observable 的订阅。过滤操作符:
filter: 过滤出符合条件的值。take: 只取前 n 个值。组合操作符:
merge: 将多个 Observable 合并成一个。concat: 按顺序串联多个 Observable。错误处理操作符:
catchError: 捕获错误并返回一个新的 Observable 或抛出错误。retry: 在发生错误时重新订阅源 Observable。代码示例
以下是一个综合使用 RxJS 核心概念和操作符的示例:
import { of, from, interval, Subject } from 'rxjs';
import { map, filter, switchMap, take, catchError } from 'rxjs/operators';
// 创建一个简单的 Observable
const observable = of(1, 2, 3, 4, 5);
observable
.pipe(
filter(x => x % 2 === 0),
map(x => x * x)
)
.subscribe(value => console.log(`Filtered and squared: ${value}`));
// 从数组创建 Observable
const arrayObservable = from([10, 20, 30, 40, 50]);
arrayObservable
.pipe(
map(x => x / 10),
take(3)
)
.subscribe(value => console.log(`Mapped and taken: ${value}`));
// 使用 interval 创建定时 Observable
const intervalObservable = interval(1000);
intervalObservable
.pipe(
take(5),
switchMap(val => of(`Interval value: ${val}`))
)
.subscribe(value => console.log(value));
// 使用 Subject 进行多播
const subject = new Subject();
subject.subscribe(value => console.log(`Observer A: ${value}`));
subject.subscribe(value => console.log(`Observer B: ${value}`));
subject.next('Hello');
subject.next('World');
通过 RxJS,开发者可以更容易地处理复杂的异步操作和事件驱动的编程模式,提高代码的可读性和可维护性。
reflect-metadata 是一个用于在 JavaScript 和 TypeScript 中实现元编程的库。它通过提供元数据反射 API,允许开发者在运行时检查和操作对象的元数据。元数据可以看作是关于程序结构的额外信息,比如类、属性或方法的注解。
核心概念
元数据 (Metadata):
反射 (Reflection):
reflect-metadata 的基本功能
定义元数据:
Reflect.defineMetadata 方法定义元数据。import 'reflect-metadata';
Reflect.defineMetadata('role', 'admin', target);
获取元数据:
Reflect.getMetadata 方法获取元数据。const role = Reflect.getMetadata('role', target);
console.log(role); // 'admin'
检查元数据:
Reflect.hasMetadata 方法检查是否存在指定的元数据。const hasRoleMetadata = Reflect.hasMetadata('role', target);
console.log(hasRoleMetadata); // true
删除元数据:
Reflect.deleteMetadata 方法删除元数据。Reflect.deleteMetadata('role', target);
const hasRoleMetadata = Reflect.hasMetadata('role', target);
console.log(hasRoleMetadata); // false
应用示例
以下是一些使用 reflect-metadata 的常见场景和示例代码:
类装饰器:
import 'reflect-metadata';
@Reflect.metadata('role', 'admin')
class User {
constructor(public name: string) {}
}
const role = Reflect.getMetadata('role', User);
console.log(role); // 'admin'
方法装饰器:
import 'reflect-metadata';
class UserService {
@Reflect.metadata('role', 'admin')
getUser() {}
}
const role = Reflect.getMetadata('role', UserService.prototype, 'getUser');
console.log(role); // 'admin'
参数装饰器:
import 'reflect-metadata';
class UserService {
getUser(@Reflect.metadata('required', true) id: number) {}
}
const requiredMetadata = Reflect.getMetadata('required', UserService.prototype, 'getUser');
console.log(requiredMetadata); // true
属性装饰器:
import 'reflect-metadata';
class User {
@Reflect.metadata('format', 'email')
email: string;
}
const formatMetadata = Reflect.getMetadata('format', User.prototype, 'email');
console.log(formatMetadata); // 'email'
完整示例
以下是一个综合使用 reflect-metadata 的示例,展示如何为类、方法和属性添加元数据并在运行时进行操作:
import 'reflect-metadata';
// 类装饰器
function Role(role: string) {
return Reflect.metadata('role', role);
}
// 方法装饰器
function Log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Calling ${propertyKey} with arguments:`, args);
return originalMethod.apply(this, args);
};
}
// 属性装饰器
function Format(format: string) {
return Reflect.metadata('format', format);
}
@Role('admin')
class User {
@Format('email')
email: string;
constructor(email: string) {
this.email = email;
}
@Log
getUserInfo() {
return `User email: ${this.email}`;
}
}
const user = new User('test@example.com');
// 获取类的元数据
const role = Reflect.getMetadata('role', User);
console.log(`Role: ${role}`); // 'Role: admin'
// 获取属性的元数据
const emailFormat = Reflect.getMetadata('format', User.prototype, 'email');
console.log(`Email format: ${emailFormat}`); // 'Email format: email'
// 调用方法,触发日志输出
console.log(user.getUserInfo());
结论
reflect-metadata 提供了一种在 JavaScript 和 TypeScript 中实现元编程的方法,使得开发者可以通过装饰器和反射 API 添加、获取和操作元数据。这在构建复杂的框架和库时非常有用,如依赖注入、路由、验证等场景。通过掌握 reflect-metadata 的使用,可以更灵活地控制和扩展应用程序的行为。
@nestjs/platform-express 是 NestJS 框架中的一个平台适配器,用于将 NestJS 应用与 Express.js 集成。NestJS 是一个基于 TypeScript 的进程框架,支持多种底层 HTTP 服务器库,如 Express 和 Fastify。@nestjs/platform-express 提供了将 NestJS 应用运行在 Express.js 之上的能力,使得开发者能够利用 Express.js 的中间件、路由等功能,同时享受 NestJS 提供的模块化、依赖注入、装饰器等高级特性。
主要功能和组成部分
ExpressAdapter:
File Upload:
@nestjs/platform-express 中的 FileInterceptor、FilesInterceptor 等装饰器和 Multer 进行文件上传处理。中间件 (Middleware):
NestMiddleware 接口和 MiddlewareConsumer 来配置中间件。静态文件服务:
代码示例
以下是一个使用 @nestjs/platform-express 构建和启动 NestJS 应用的示例:
基本应用示例:
import { Module, Controller, Get, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { ExpressAdapter } from '@nestjs/platform-express';
import * as express from 'express';
// 控制器
@Controller()
class AppController {
@Get()
getHello(): string {
return 'Hello World!';
}
}
// 模块
@Module({
controllers: [AppController],
})
class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
// 配置中间件
}
}
// 创建和启动应用
async function bootstrap() {
const server = express();
const app = await NestFactory.create(AppModule, new ExpressAdapter(server));
await app.listen(3000);
console.log('Application is running on: http://localhost:3000');
}
bootstrap();
文件上传示例:
import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
import { extname } from 'path';
@Controller('upload')
class UploadController {
@Post('single')
@UseInterceptors(FileInterceptor('file', {
storage: diskStorage({
destination: './uploads',
filename: (req, file, callback) => {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
const ext = extname(file.originalname);
callback(null, `${file.fieldname}-${uniqueSuffix}${ext}`);
}
})
}))
uploadFile(@UploadedFile() file) {
console.log(file);
return { message: 'File uploaded successfully!', file };
}
}
@Module({
controllers: [UploadController],
})
class UploadModule {}
async function bootstrap() {
const app = await NestFactory.create(UploadModule);
await app.listen(3000);
console.log('Application is running on: http://localhost:3000');
}
bootstrap();
静态文件服务示例:
import { Module, Controller, Get, MiddlewareConsumer, NestModule } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { join } from 'path';
import { ExpressAdapter } from '@nestjs/platform-express';
import * as express from 'express';
@Controller()
class AppController {
@Get()
getHello(): string {
return 'Hello World!';
}
}
@Module({
controllers: [AppController],
})
class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
// 配置静态文件服务
const server = consumer.apply().getInstance();
server.use('/static', express.static(join(__dirname, '..', 'public')));
}
}
async function bootstrap() {
const server = express();
const app = await NestFactory.create(AppModule, new ExpressAdapter(server));
await app.listen(3000);
console.log('Application is running on: http://localhost:3000');
}
bootstrap();
结论
@nestjs/platform-express 提供了将 NestJS 与 Express.js 集成的能力,使得开发者可以利用 Express.js 的强大功能,同时享受 NestJS 带来的模块化、依赖注入和装饰器等高级特性。通过使用 @nestjs/platform-express,开发者可以轻松构建高效、可扩展的 Web 应用程序。
NestFactory 是 NestJS 框架中用于创建 Nest 应用实例的核心类。它提供了一组静态方法,用于引导和启动应用程序。通过 NestFactory,你可以创建 HTTP 服务、微服务以及独立的应用实例。
主要方法
create:
static async create<T>(module: Type<T>, options?: NestApplicationOptions): Promise<INestApplication>;
createMicroservice:
static createMicroservice<T>(module: Type<T>, options: MicroserviceOptions): INestMicroservice;
createApplicationContext:
static async createApplicationContext<T>(module: Type<T>, options?: NestApplicationContextOptions): Promise<INestApplicationContext>;
创建一个 HTTP 服务
通过 NestFactory.create 方法可以创建一个 HTTP 服务。下面是一个简单的示例:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
console.log('Application is running on: http://localhost:3000');
}
bootstrap();
在这个示例中:
NestFactory.create(AppModule) 创建了一个 Nest 应用实例。app.listen(3000) 启动应用,监听 3000 端口。创建一个微服务
通过 NestFactory.createMicroservice 方法可以创建一个微服务。下面是一个简单的示例:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { Transport, MicroserviceOptions } from '@nestjs/microservices';
async function bootstrap() {
const app = await NestFactory.createMicroservice<MicroserviceOptions>(AppModule, {
transport: Transport.TCP,
});
app.listen(() => console.log('Microservice is listening'));
}
bootstrap();
在这个示例中:
NestFactory.createMicroservice 创建了一个 TCP 传输的微服务实例。app.listen 启动微服务。创建一个独立的应用上下文
通过 NestFactory.createApplicationContext 方法可以创建一个独立的应用上下文,适用于运行任务或进行测试。下面是一个简单的示例:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const appContext = await NestFactory.createApplicationContext(AppModule);
const appService = appContext.get(AppService);
appService.runTask();
await appContext.close();
}
bootstrap();
在这个示例中:
NestFactory.createApplicationContext(AppModule) 创建了一个应用上下文实例。appContext.get(AppService) 获取服务实例并运行任务。常见选项
logger:
const app = await NestFactory.create(AppModule, {
logger: ['error', 'warn'],
});
bodyParser:
const app = await NestFactory.create(AppModule, {
bodyParser: false, // 禁用 bodyParser
});
总结
NestFactory 是创建和启动 NestJS 应用的核心工具。它提供了多种方法,适用于不同类型的应用程序,包括 HTTP 服务、微服务和独立的应用上下文。通过理解和使用 NestFactory,开发者可以高效地引导和管理 NestJS 应用程序。
@Module 是 NestJS 框架中的一个装饰器,用于定义模块。模块是组织代码的基本单元,它们将相关的组件(如控制器、服务、提供者等)组合在一起。NestJS 的模块系统受到了 Angular 的启发,旨在促进代码的模块化和可维护性。
核心概念
模块装饰器 (@Module):
模块元数据:
imports: 导入的模块列表,这些模块的提供者可以在当前模块中使用。controllers: 当前模块定义的控制器。providers: 当前模块定义的提供者(服务等),这些提供者可以注入到模块的其他组件中。exports: 当前模块提供并可以在其他模块中使用的提供者。使用示例
以下是一个基本的模块示例:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
在这个示例中:
@Module 装饰器定义了 AppModule 类为一个模块。imports 数组为空,表示没有导入其他模块。controllers 数组包含了 AppController,这是一个控制器。providers 数组包含了 AppService,这是一个提供者(服务)。模块的详细示例
下面是一个更复杂的示例,展示了如何使用多个模块、控制器和服务:
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
@Module({
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}
import { Controller, Get } from '@nestjs/common';
import { UsersService } from './users.service';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
findAll() {
return this.usersService.findAll();
}
}
import { Injectable } from '@nestjs/common';
@Injectable()
export class UsersService {
private readonly users = [{ id: 1, name: 'John Doe' }];
findAll() {
return this.users;
}
}
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UsersModule } from './users/users.module';
@Module({
imports: [UsersModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
模块元数据详解
imports:
imports 数组进行管理。@Module({
imports: [UsersModule],
})
export class AppModule {}
controllers:
@Module({
controllers: [AppController],
})
export class AppModule {}
providers:
@Module({
providers: [AppService],
})
export class AppModule {}
exports:
@Module({
providers: [AppService],
exports: [AppService],
})
export class AppModule {}
总结
@Module 是 NestJS 框架中用于定义模块的装饰器。通过模块,开发者可以将相关的控制器、服务和其他组件组织在一起,提高代码的模块化和可维护性。模块的 imports、controllers、providers 和 exports 元数据属性使得模块之间可以相互依赖和协作,形成一个高内聚、低耦合的应用架构。
@Controller 是 NestJS 框架中的一个装饰器,用于定义控制器。控制器是处理传入 HTTP 请求的核心组件。每个控制器负责处理特定的请求路径和相应的 HTTP 方法。控制器使用路由装饰器(如 @Get、@Post 等)来定义路由和请求处理方法。
基本使用
import { Controller, Get } from '@nestjs/common';
@Controller('users')
export class UsersController {
@Get()
findAll(): string {
return 'This action returns all users';
}
}
在这个示例中:
@Controller('users') 装饰器将 UsersController 类标记为一个控制器,并将基本路径设为 users。@Get() 装饰器将 findAll 方法映射到 HTTP GET 请求。详细示例
import { Controller, Get, Post, Body, Param } from '@nestjs/common';
import { CreateUserDto } from './create-user.dto';
@Controller('users')
export class UsersController {
@Get()
findAll(): string {
return 'This action returns all users';
}
@Get(':id')
findOne(@Param('id') id: string): string {
return `This action returns user #${id}`;
}
@Post()
create(@Body() createUserDto: CreateUserDto): string {
return 'This action adds a new user';
}
}
在这个示例中:
@Get() 装饰器将 findAll 方法映射到没有参数的 HTTP GET 请求。@Get(':id') 装饰器将 findOne 方法映射到具有 id 参数的 HTTP GET 请求。@Post() 装饰器将 create 方法映射到 HTTP POST 请求,并从请求体中提取数据。
使用 DTO(数据传输对象):
export class CreateUserDto {
readonly name: string;
readonly age: number;
}
在控制器中,使用 @Body() 装饰器提取请求体数据并将其映射到 DTO。
常用装饰器
路由前缀
可以为控制器定义路由前缀,这样所有的路由都将基于该前缀。
@Controller('users')
export class UsersController {
@Get()
findAll(): string {
return 'This action returns all users';
}
}
在这个例子中,UsersController 的所有路由都将基于 users 前缀,例如 GET /users 将调用 findAll 方法。
分组路由
通过路由前缀,可以将相关的路由分组到一个控制器中,便于管理和维护。
@Controller('users')
export class UsersController {
@Get()
findAll(): string {
return 'This action returns all users';
}
@Get(':id')
findOne(@Param('id') id: string): string {
return `This action returns user #${id}`;
}
@Post()
create(@Body() createUserDto: CreateUserDto): string {
return 'This action adds a new user';
}
}
通过上述代码,GET /users 将调用 findAll 方法,GET /users/:id 将调用 findOne 方法,POST /users 将调用 create 方法。
结论
@Controller 是 NestJS 框架中用于定义控制器的装饰器。控制器负责处理传入的 HTTP 请求,并返回响应。通过使用各种装饰器(如 @Get、@Post、@Param 等),可以方便地定义和管理路由及其对应的处理方法。控制器将请求映射到处理程序,使得应用程序的结构更加清晰和模块化。
@Get 是 NestJS 框架中的一个装饰器,用于将控制器方法映射到 HTTP GET 请求。这个装饰器是由 @nestjs/common 模块提供的。通过使用 @Get 装饰器,可以指定该方法处理特定路径上的 GET 请求。
基本用法
import { Controller, Get } from '@nestjs/common';
@Controller('users')
export class UsersController {
@Get()
findAll(): string {
return 'This action returns all users';
}
}
在这个示例中:
@Controller('users') 将 UsersController 类定义为一个控制器,并将其基本路径设为 users。@Get() 装饰器将 findAll 方法映射到 GET /users 请求。处理带参数的 GET 请求
可以通过在 @Get 装饰器中指定路径参数来处理带参数的 GET 请求。
import { Controller, Get, Param } from '@nestjs/common';
@Controller('users')
export class UsersController {
@Get(':id')
findOne(@Param('id') id: string): string {
return `This action returns user #${id}`;
}
}
在这个示例中:
@Get(':id') 装饰器将 findOne 方法映射到 GET /users/:id 请求,其中 :id 是一个路由参数。@Param('id') 装饰器用于提取请求路径中的 id 参数。处理带查询参数的 GET 请求
可以通过使用 @Query 装饰器来提取查询参数。
import { Controller, Get, Query } from '@nestjs/common';
@Controller('users')
export class UsersController {
@Get()
findAll(@Query('age') age: string): string {
return `This action returns users of age ${age}`;
}
}
在这个示例中:
@Query('age') 装饰器用于提取请求 URL 中的查询参数 age。GET /users?age=25 将调用 findAll 方法,并传递 age 参数的值。组合使用路径和查询参数
可以同时使用路径参数和查询参数来处理更复杂的请求。
import { Controller, Get, Param, Query } from '@nestjs/common';
@Controller('users')
export class UsersController {
@Get(':id')
findOne(@Param('id') id: string, @Query('includePosts') includePosts: boolean): string {
return `This action returns user #${id} with includePosts=${includePosts}`;
}
}
在这个示例中:
@Get(':id') 装饰器将 findOne 方法映射到 GET /users/:id 请求。@Param('id') 和 @Query('includePosts') 分别用于提取路径参数和查询参数。完整示例
以下是一个完整的示例,展示了如何在控制器中使用 @Get 装饰器处理不同的 GET 请求:
import { Controller, Get, Param, Query } from '@nestjs/common';
@Controller('users')
export class UsersController {
// 处理没有参数的 GET 请求
@Get()
findAll(): string {
return 'This action returns all users';
}
// 处理带路径参数的 GET 请求
@Get(':id')
findOne(@Param('id') id: string): string {
return `This action returns user #${id}`;
}
// 处理带查询参数的 GET 请求
@Get()
findByAge(@Query('age') age: string): string {
return `This action returns users of age ${age}`;
}
// 处理带路径和查询参数的 GET 请求
@Get(':id/details')
findOneWithDetails(@Param('id') id: string, @Query('includePosts') includePosts: boolean): string {
return `This action returns user #${id} with includePosts=${includePosts}`;
}
}
在这个示例中:
findAll 方法处理没有参数的 GET 请求。findOne 方法处理带路径参数的 GET 请求。findByAge 方法处理带查询参数的 GET 请求。findOneWithDetails 方法处理带路径和查询参数的 GET 请求。总结
@Get 是一个用于处理 HTTP GET 请求的装饰器,通过它可以轻松地将控制器方法映射到特定的请求路径。通过结合使用 @Param 和 @Query 等装饰器,可以灵活地处理各种类型的 GET 请求。使用 @Get 装饰器,可以使代码更加模块化和易于维护。
esModuleInterop 和 allowSyntheticDefaultImports两个选项都是 TypeScript 编译器选项,用于处理 ES6 模块和 CommonJS 模块之间的兼容性问题。它们的主要目的是让 TypeScript 更容易与使用不同模块系统的 JavaScript 代码库进行互操作,但它们的作用和影响有所不同。
相同点
模块兼容性:
启用方式:
esModuleInterop,通常不需要再单独启用 allowSyntheticDefaultImports,因为 esModuleInterop 已经包含了 allowSyntheticDefaultImports 的功能。不同点
作用范围:
allowSyntheticDefaultImports:
default 导出,TypeScript 也会假设它有一个,并允许 import 语句使用默认导入。esModuleInterop:
allowSyntheticDefaultImports。它的作用不仅仅限于允许默认导入,还包括重新调整 TypeScript 对模块的导入和导出行为,使其更符合 ES6 规范。export = 的模块生成默认导出,确保这些模块在 TypeScript 中可以使用默认导入语法。编译器行为:
allowSyntheticDefaultImports:
esModuleInterop:
示例
假设我们有一个 CommonJS 模块 commonjs-module.js:
// commonjs-module.js
module.exports = { foo: 'bar' };
allowSyntheticDefaultImports:{
"compilerOptions": {
"allowSyntheticDefaultImports": true
}
}
在 TypeScript 中:
import commonjsModule from './commonjs-module';
console.log(commonjsModule.foo); // 'bar'
编译后:
const commonjs_module_1 = require('./commonjs-module');
console.log(commonjs_module_1.default.foo); // 这里会报错,因为 `commonjs-module.js` 没有 `default` 导出
esModuleInterop(隐含包含 allowSyntheticDefaultImports):{
"compilerOptions": {
"esModuleInterop": true
}
}
在 TypeScript 中:
import commonjsModule from './commonjs-module';
console.log(commonjsModule.foo); // 'bar'
编译后:
const tslib_1 = require('tslib');
const commonjs_module_1 = tslib_1.__importDefault(require('./commonjs-module'));
console.log(commonjs_module_1.default.foo); // 正确,因为 `__importDefault` 函数创建了一个默认导出
总结
相同点:
不同点:
allowSyntheticDefaultImports 仅仅允许使用默认导入语法,但不改变编译输出。esModuleInterop 不仅允许使用默认导入语法,还会调整编译输出,使其与 ES6 模块行为一致,并包含了 allowSyntheticDefaultImports 的功能。在现代 TypeScript 项目中,通常推荐启用 esModuleInterop,以便更好地支持模块互操作,并使编译后的代码更符合 ES6 模块规范。