# TS Config
# 构建相关
- 特殊语法相关
- experimentalDecorators 与 emitDecoratorMetadata
- jsx、jsxFactory、jsxFragmentFactory 与 jsxImportSource
- target 与 lib、noLib
- 构建解析相关
- files、include 与 exclude
- exclude 只能剔除已经被 include 包含的文件
- baseUrl
- rootDir
- rootDirs
- types 与 typeRoots
- moduleResolution
- moduleSuffixes
- noResolve
- paths
- resolveJsonModule
- files、include 与 exclude
- 构建产物相关
- 构建输出相关
- outDir 与 outFile
- preserveConstEnums
- noEmit 与 noEmitOnError
- module
- importHelpers 与 noEmitHelpers
- downlevelIteration
- importsNotUsedAsValues 与 preserveValueImports
- 构建输出相关
- 声明文件相关
- declaration、declarationDir
- declarationMap
- emitDeclarationOnly
- Source Map 相关
- sourceMap 与 inlineSourceMap
- sourceRoot 与 mapRoot
- 构建产物代码格式化配置
- newLine
- removeComments
- stripInternal
# 检查相关
- 允许类
- allowUmdGlobalAccess
- allowUnreachableCode
- allowUnusedLabels
- 禁止类
- 主要关注未被妥善处理的逻辑代码与无类型信息(手动标注与自动推导均无)的部分
- 类型检查
- noImplicitAny
- useUnknownInCatchVariables
- 逻辑检查
- noFallthroughCasesInSwitch
- noImplicitOverride
- noImplicitReturns
- noImplicitThis
- noPropertyAccessFromIndexSignature 与 noUncheckedIndexedAccess
- noUnusedLocals 与 noUnusedParameters
- 严格检查
- exactOptionalPropertyTypes
- alwaysStrict
- strict
- strictBindCallApply
- strictFunctionTypes
- strictNullChecks
- strictPropertyInitialization
- skipLibCheck 与 skipDefaultLibCheck
# 工程相关
Project References
- 可以将整个工程拆分成多个部分,比如你的 UI 部分、Hooks 部分以及主应用等等
- 和 Monorepo 非常相似,但它并不需要各个子项目拥有自己独立的 package.json、独立安装依赖、独立构建等
- 可以使用完全独立的 TSConfig 配置文件,也可以使用一个 TSConfig 配置文件
{
"references": [
{ "path": "../ui" },
{ "path": "../hooks" },
{ "path": "../app" }
]
}
composite
# JavaScript 相关
- allowJs
- checkJs
# 模块相关
- esModuleInterop 与 allowSyntheticDefaultImports
# 编译器相关
- incremental
- watch 相关
- 编译器检查
# 其他工程相关
- extends
# Prisma NestJS 实战
# Heroku 环境配置
# NestJS
新建项目:
代码语言:javascript复制npm i -g @nestjs/cli
nest new nest-prisma
主要文件结构:
app.controller.ts
API 路由定义文件- 一般不在 Controller 中处理业务逻辑,Controller 通常只处理请求入参的校验、请求响应的包装
app.service.ts
在 Service 层去处理数据库交互、BFF、日志等逻辑,然后供 Controller 层调用- 注意,不意味着 Controller 层有一个
UpdateUser
处理方法,那 Service 层也要有专门的UpdateUser
方法,更好的方法是将 Service 拆得更细一些,在未来新增 Controller 时,只需要按照逻辑重新组装 Service 即可
- 注意,不意味着 Controller 层有一个
app.module.ts
应用的核心文件,需要这个模块才能在main.ts
中去启动应用- 在实际中,可能会有多个
.module.ts
文件来实现对业务逻辑的模块拆分,如user.module.ts
、upload.module.ts
等 - 在这个文件中会定义属于该模块的 Controller 和 Service,其他模块可以通过导入该模块来使用其内部的 Service,而不是直接导入 Service 造成模块间的混乱引用
- 在实际中,可能会有多个
main.ts
应用的入口文件,负责启动应用- 定义全局级别的应用配置
# Prisma
ORM 库(Object-Relational Mapping),其实就是编程语言到 SQL 的映射,无需学习 SQL 的使用,直接用最熟悉的代码调用方法,即可与数据库进行交互。
NodeJs 中的 ORM 目前基本都是通过 js / ts 文件进行定义的,比如 Sequelize、TypeORM 等,均是通过面向对象的方式进行数据库实体的定义。
Prisma 最特殊的一点,它使用自己的 SDL(Schema Define Language,也可以说是 DSL ,Domain-Specified Language)来声明一个实体。
初始化 Prisma:
代码语言:javascript复制npx prisma init
npm i prisma -g
npm i @prisma/client -D
声明 Schema:
代码语言:javascript复制// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Tag {
id String @id @default(cuid())
name String
description String?
Article Article[]
}
model Category {
id String @id @default(cuid())
name String
description String?
Article Article[]
}
model Article {
id Int @id @default(autoincrement())
title String?
description String @default("there is no description")
content String
visible Boolean @default(true)
tag Tag[]
category Category[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
生成 Client:
代码语言:javascript复制prisma generate
Prisma Client 会被生成到 node_modules/@prisma/client
目录下,可以通过 import { PrismaClient } from '@prisma/client'
来引入。
# NestJS 中集成 Prisma
将 Prisma 相关逻辑封装到 Service 中:
代码语言:javascript复制import {
Injectable,
OnApplicationShutdown,
OnApplicationBootstrap,
} from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
@Injectable()
export class PrismaService
extends PrismaClient
implements OnApplicationBootstrap, OnApplicationShutdown
{
constructor() {
super();
}
async onApplicationBootstrap() {
await this.$connect();
}
async onApplicationShutdown(signal?: string) {
await this.$disconnect();
}
}
实例化:
代码语言:javascript复制import { Global, Module } from '@nestjs/common';
import { PrismaService } from './prisma.service';
@Global()
@Module({
providers: [PrismaService],
exports: [PrismaService],
})
export default class PrismaModule {}
在 app.module.ts
中导入:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import PrismaModule from './data/prisma.module';
@Module({
imports: [
PrismaModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
声明相关类型:
代码语言:javascript复制export type { Article, Tag, Category } from '@prisma/client';
import type { Prisma } from '@prisma/client';
export type ArticleCreateInput = Prisma.ArticleCreateInput;
export type ArticleUpdateInput = Prisma.ArticleUpdateInput &
Prisma.ArticleWhereUniqueInput;
export type TagCreateInput = Prisma.TagCreateInput;
export type TagUpdateInput = Prisma.TagUpdateInput & Prisma.TagWhereUniqueInput;
export type CategoryCreateInput = Prisma.CategoryCreateInput;
export type CategoryUpdateInput = Prisma.CategoryUpdateInput &
Prisma.CategoryWhereUniqueInput;
export type MaybeArray<T> = T | T[];
export type MaybeNull<T> = T | null;