掘金 后端 ( ) • 2024-04-06 12:03

theme: channing-cyan highlight: ocean

欢迎订阅Nest.js口袋书专栏

如果您觉得这篇文章有帮助的话!给个点赞和评论支持下吧,感谢~

作者:前端小王hs

阿里云社区博客专家/清华大学出版社签约作者✍/者作问访万百NDSC/B站千粉前端up主

人生若只如初见

基础结构

当使用nest new project-name这个由Nest CLI提供的命令后,会在当前目录下新建一个名由自定义的project-name的目录,里面的文件结构如下图所示:

基础结构

下面,让我们一起(由上到下)分析根目录内的文件(夹)

node_modules

当通过npmyarnpnpm这些包管理器安装依赖项时,会自动生成此文件用于存放项目所使用的依赖文件

src

项目的核心目录,关于这一点,我们会在第4节核心目录进行介绍

test

用于存放测试文件的目录,这也是nest与其他框架不同的一点,即鼓励开发者编写测试逻辑。在后续的实战中,我们也会在nest中进行测试,保证代码的质量和可维护性

.eslintrc.js

通过名字我们可以知道这是与ESLint相关的文件,ESLint是一个开源的JavaScript代码检查工具,主要用于代码的规范,由此可见nest对代码的要求性。

而当前文件正是ESLint的配置文件,允许我们自定义ESLint的行为,下面我们来看下里面的代码:

module.exports = {
  parser: '@typescript-eslint/parser',
  parserOptions: {
    project: 'tsconfig.json',
    tsconfigRootDir: __dirname,
    sourceType: 'module',
  },
  plugins: ['@typescript-eslint/eslint-plugin'],
  extends: [
    'plugin:@typescript-eslint/recommended',
    'plugin:prettier/recommended',
  ],
  root: true,
  env: {
    node: true,
    jest: true,
  },
  ignorePatterns: ['.eslintrc.js'],
  rules: {
    '@typescript-eslint/interface-name-prefix': 'off',
    '@typescript-eslint/explicit-function-return-type': 'off',
    '@typescript-eslint/explicit-module-boundary-types': 'off',
    '@typescript-eslint/no-explicit-any': 'off',
  },
};

由于注释较长,所以笔者将代码所表达或实现的内容写在下面:

(1)parser:意为解析,在代码中使用了@typescript-eslint/parser,用于ESLint解析TypeScript代码

(2)parserOptionsproject指定了TypeScript的配置文件,也就是根目录中的tsconfig.json;tsconfigRootDir是指TypeScript的配置文件在哪个目录,这里是__dirname,也就是当前目录;sourceType则是告诉ESLint源代码类型是模块,这里指的是使用了ES6module特性,如果是使用的Node.js默认的CommonJS,则无需添加sourceType

(3)plugins:即插件,这里使用了@typescript-eslint/eslint-plugin,这个插件设计了很多针对TypeScriptESLint规则

(4)extends:使用已经存在的规则,与之相对的是需要开发者自定义的规则。在文件中是使用了@typescript-eslintprettier推荐的规则

(5)root:意为“根”,就是标记当前目录为ESLint的根目录

(6)env:使用的全局变量和环境。在文件中启用了nodejest的全局变量和环境,一个简单的例子就是在(2)中的__dirname,它就是Node.js特有的一个全局变量

(7)ignorePatterns:ignore意为忽略,其实就是忽略对某个文件的检查,在文件中就是忽略对自身的检查

(8)rules:默认定义的自定义ESLint规则,可以看到都是false

第一个是interface-name-prefix,在一些严格的项目中,要求interface的名字前缀具有某些规则,这里取消了这个要求

第二个是explicit-function-return-type,要求函数是否有显式的返回类型,这里为false这其实非常宽松

第三个是explicit-module-boundary-types,要求模块导出时是否具有显式的类型,这里为false

第四个是是否禁止使用显式的any类型,也就是是否要禁止出现anyScript这种情况,这里为false

可以看到这些规则还是保留了开发时的宽松风格,这里不得不提的就是很多初级开发者ESLint较为反感,在使用脚手架搭建项目时都不添加ESLint。从长期看,这对自己的开发生涯并不十分有利,所以笔者还是建议养成良好的代码风格,不管是进入大厂,又或当自己有朝一日成为项目总监时,都是十分有好处的

.gitignore

看名字就知道,这是一个与git相关的文件,没错!这个文件主要是用于设定将代码上传至远程仓库时,哪些文件是无需上传的

举个简单的例子,我们知道node_modules由于存放的都是项目依赖,所以导致该文件目录十分大,也因为如此,该文件通常不会上传至远程仓库,那么就可以在.gitignore中添加node_modules。事实上,该文件通常都会带上node_modules,即使是由脚手架自动生成的

node_modules

那么问题来了,读者知道上图中的/dist/build是什么用途的文件吗?

.prettierrc

Prettier是一个代码格式化的工具,而该文件就是配置文件。代码非常简单,如下所示:

{
  "singleQuote": true,
  "trailingComma": "all"
}

singleQuote是说代码中的字符串应该由单引号包裹而不是双引号,代码如下:

const name = '前端小王hs'

trailingComma是指数组或对象的最后一个元素是否还要添加逗号,代码如下:

const obj = {
  name:'前端小王hs',
  age:24,
}

nest-cli.json

这是Nest CLI的配置文件,这里我们主要注意后两个属性,即sourceRootcompilerOptions,前者主要是定义了项目的根目录,当执行打包等命令时,nest会从该属性值去执行命令,在文件中即为根目录srccompilerOptions则是可以自定义编译选项,这里的deleteOutDirtrue是指编译前删除输出目录,这里的输出目录即我们之前提到的dist,那么您猜对答案了吗!

package.json

这是Node.js的核心文件,那么在里面包括了项目的名称、版本、描述、入口文件、使用的依赖等,其实就是我们在使用npm init命令时输入的内容

pnpm-lock.yaml

保存了依赖的锁定版本信息

笔者注:在笔者的新书中将会对npmyarnpnpm三个包管理器的出现、常规命令、优缺点进行了详细的介绍,那么就包括了为什么需要进行锁定版本的内容介绍,对感兴趣的朋友可以关注笔者获取第一时间的出版讯息

README.md

这是一个Markdown格式的文档,通常用于介绍项目的架构功能启动命令开源协议等内容

tsconfig.build.json

这是一个TypeScript的配置文件,主要是用于拓展或覆盖默认的tsconfig.json文件,例如在不同的环境下,可能需要不同的TS配置,就可以在该文件中对原有配置进行覆盖或者说修改

我们直接看代码

{
  "extends": "./tsconfig.json",
  "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
}

第一个属性extends其实就是说使用了默认的tsconfig.json文件;第二个属性则排除了无需编译的文件

tsconfig.json

TypeScript的主要配置文件,我们主要从默认的配置项中进行分析,代码如下:

  "compilerOptions": {
    // 使用CommonJS的模块体系
    "module": "commonjs",
    // 生成.d.ts声明文件 
    "declaration": true,
    // 生成JS文件时移除所有注释
    "removeComments": true,
    // 为装饰器提供元数据支持
    "emitDecoratorMetadata": true,
    // 提供对装饰器的实验性支持
    "experimentalDecorators": true,
    // 允许在没有默认导出的模块中默认导入
    "allowSyntheticDefaultImports": true,
    // 代码符合ES2021规范
    "target": "ES2021",
    // 生成源映射文件.map
    "sourceMap": true,
    // 编译后的输出目录
    "outDir": "./dist",
    // 用于解析时的基准目录
    "baseUrl": "./",
    // 增量编译
    "incremental": true,
    // 跳过所有声明文件的类型检查
    "skipLibCheck": true,
    // 不启用严格Null检查
    "strictNullChecks": false,
    // 不会隐式添加any类型
    "noImplicitAny": false,
    // 不启用bind/call/apply的严格检查
    "strictBindCallApply": false,
    // 不强调在文件引用中使用一致性的大小写
    "forceConsistentCasingInFileNames": false,
    // 假设switch中存在case但没有break,不报错
    "noFallthroughCasesInSwitch": false
  }

对于TypeScript的更多配置内容,读者可通过学习TypeScript进行了解,笔者在这里就不过的叙述了,如果在后续的代码实战中有需要,读者会对使用的TypeScript进行介绍

本篇最后

码字不易,这一过程涉及到如何将晦涩的概念以通俗的言语表达出来,如果感觉这篇文章对您有帮助,笔者希望能得到您的评论+关注!您的评论+关注是我更文的最大动力!

如果您发现有错字,还请见谅并给予指正建议,笔者会在最短时间内修改并私聊感谢

如果由于不可抗拒因素导致拖更,还请您见谅!

如果需进一步技术交流,请您在首页联系方式内联系我!