跳到主要内容

Node.js环境搭建及前后端应用初始化

环境准备

安装和配置 pnpm

执行命令:npm install -g pnpm

执行命令: pnpm setup , 会出现如下:

Appended new lines to /Users/jie.xu/.zshrc

Next configuration changes were made:
export PNPM_HOME="/Users/jie.xu/Library/pnpm"
case ":$PATH:" in
*":$PNPM_HOME:"*) ;;
*) export PATH="$PNPM_HOME:$PATH" ;;
esac

To start using pnpm, run:
source /Users/jie.xu/.zshrc

按要求执行一下 source 命令: source ~/.zshrc

然后指定 pnpm 的版本,可以用 LTS 版本: pnpm env use --global lts

或者最新版本:pnpm env use --global latest

创建并启动项目

创建应用

找到合适的目录,比如我这里是: ~/coding/full-stack/3rclass/chapter1:

执行命令:mkdir nodeapp && cd $_ 创建应用目录并打开目录

pnpm init 初始化一个node应用以生成package.json

pnpm add fastify 安装fastify框架 执行完之后,大概目录结构如下:

(base) ➜  nodeapp tree
.
├── node_modules
│   └── fastify -> .pnpm/fastify@4.28.1/node_modules/fastify
├── package.json
└── pnpm-lock.yaml

3 directories, 2 files

安装typescript和node类型库: pnpm add -D typescript @types/node

(base) ➜  nodeapp tree
.
├── node_modules
│   ├── @types
│   │   └── node -> ../.pnpm/@types+node@20.14.9/node_modules/@types/node
│   ├── fastify -> .pnpm/fastify@4.28.1/node_modules/fastify
│   └── typescript -> .pnpm/typescript@5.5.3/node_modules/typescript
├── package.json
└── pnpm-lock.yaml

6 directories, 2 files

初始化typescript以生成tsconfig.json: pnpm --package=typescript dlx tsc --init

配置 TS

把以下配置放入tsconfig.json中。tsconfig.json此处并非作为真正的ts -> js的编译过程的配置文件,而仅仅作为vscode的ts-server的代码编辑和检测功能以及eslint的ts解析器的配置使用

对于这些TS的每个配置的作用,不在本课的解释范围内,请自行查看此处官网文档

{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"strict": true,
"alwaysStrict": true,
"target": "esnext",
"module": "commonjs",
"moduleResolution": "Node",
"allowJs": true,
"noEmit": false,
"declaration": true,
"declarationMap": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"incremental": true,
"skipLibCheck": true,
"strictNullChecks": false,
"noImplicitAny": true,
"strictBindCallApply": false,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": false,
"isolatedModules": true,
"esModuleInterop": true,
"noUnusedLocals": true,
"noImplicitReturns": true,
"pretty": true,
"resolveJsonModule": true,
"importsNotUsedAsValues": "remove",
"baseUrl": ".",
"outDir": "./dist",
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src", "test", "typings/**/*.d.ts", "**/*spec.ts", "**.js"]
}

添加一个tsconfig.build.json文件,作为ts -> js 的编译工作配置,其内容如下

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

此处我们排除了**.js,以防止.eslintrc.js等文件被编译进应用中,而在tsconfig.json中我们需要加上才可以自动格式化这些文件。因为eslint是使用tsconfig.json作为ts的解析配置的

bun

为了在开发时直接运行ts文件并且实现热重载,我们使用bun

安装:curl https://bun.sh/install | bash 添加到 Path: export PATH="$HOME/.bun/bin:$PATH" source: source ~/.zshrc # or source ~/.bashrc depending on your shell 检查:

(base) ➜  nodeapp bun --version

1.1.18

此处使用bun纯粹是为了方便,如果需要类型检测则可以使用ts-node+nodemon来代替。关于bun和nodemon我们后续会在课程中专门讲解

此处不在全局中安装bun,而是简单地在项目中安装.同时,添加了bun的typescript类型库: pnpm add bun @types/bun -D

(base) ➜  nodeapp tree
.
├── node_modules
│   ├── @types
│   │   ├── bun -> ../.pnpm/@types+bun@1.1.6/node_modules/@types/bun
│   │   └── node -> ../.pnpm/@types+node@20.14.9/node_modules/@types/node
│   ├── bun -> .pnpm/bun@1.1.18/node_modules/bun
│   ├── fastify -> .pnpm/fastify@4.28.1/node_modules/fastify
│   └── typescript -> .pnpm/typescript@5.5.3/node_modules/typescript
├── package.json
├── pnpm-lock.yaml
└── tsconfig.json

应用代码

本节应用代码非常简单,只是启动一个fastify的服务器

// src/main.ts
import fastify from "fastify";

const server = fastify();

server.get("/", async (request, reply) => {
return "hello world!\n";
});

server.listen({ port: 8080 }, (err, address) => {
if (err) {
console.error(err);
process.exit(1);
}
console.log('Server listening at http://127.0.0.1:8080');
});

编译启动

添加以下脚本到package.json

{
"scripts": {
"dev": "pnpm start:dev",
"build": "tsc -p tsconfig.build.json",
"start:dev": "bun --watch src/main.ts",
"start": "node dist/main.js"
},
}

首先尝试编译命令: pnpm build,可以看到以下编译产出了 dist文件夹

├── dist
│   ├── main.d.ts
│   ├── main.d.ts.map
│   ├── main.js
│   ├── main.js.map
│   └── tsconfig.build.tsbuildinfo
├── node_modules
│   ├── @types
│   │   ├── bun -> ../.pnpm/@types+bun@1.1.6/node_modules/@types/bun
│   │   └── node -> ../.pnpm/@types+node@20.14.9/node_modules/@types/node
│   ├── bun -> .pnpm/bun@1.1.18/node_modules/bun
│   ├── fastify -> .pnpm/fastify@4.28.1/node_modules/fastify
│   └── typescript -> .pnpm/typescript@5.5.3/node_modules/typescript
├── package.json
├── pnpm-lock.yaml
├── src
│   └── main.ts
├── tsconfig.build.json
└── tsconfig.json

10 directories, 10 files

运行 dist/main.js

pnpm start

然后在浏览器中访问127.0.0.1:8080即可看到输出了”Hello World!“

按ctrl+c关闭node进程,然后使用bun启动开发环境

尽量不要使用bun --hot,因为这没有重新加载进程,只是替换了模块。这个操作比较适合前端,不适合node。

优化仓库

代码格式化

使用eslint对代码进行风格化(形成属于自己或自己团队的一种固有的代码风格),而prettier可以对代码进行美化。一般我们会整合这两者来使用,对代码进行格式化。

安装必要的依赖:

pnpm add -D jest

pnpm add eslint@8.57.0 \
prettier \
@typescript-eslint/parser \
@typescript-eslint/eslint-plugin \
eslint-config-airbnb-base \
eslint-config-airbnb-typescript \
eslint-config-prettier \
eslint-plugin-import \
eslint-plugin-prettier \
eslint-plugin-unused-imports \
eslint-plugin-jest
jest -D

由于目前eslint最新版本已到9,而很多插件还不兼容最新版。所以要对其做以下版本升级忽略(在pnpm up --latest时忽略eslint的升级)就需要修改package.json文件

{
// ...
"pnpm": {
"updateConfig": {
"ignoreDependencies": [
"eslint"
]
}
}
}

如果出现unmet peer警告,就把该peer依赖的版本忽略掉,比如

{
"pnpm": {
// ...
"peerDependencyRules": {
"allowAny": [
"@typescript-eslint/eslint-plugin"
]
}
}
}

然后执行pnpm up --latest把所以依赖升级到最新版

创建.eslintrc.js和.prettierrc.js,用于配置eslint和pretter。eslint采用airbnb 的 ESLint 规则并整合 Prettier,并且经过一定的客制化同时配合 VSCode 可达到完美的编码体验

Eslint配置

// .eslintrc.js
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
parserOptions: {
project: true,
ecmaVersion: 'latest',
sourceType: 'module',
},
plugins: ['@typescript-eslint', 'jest', 'import', 'unused-imports', 'prettier'],
extends: [
// airbnb规范
// https://www.npmjs.com/package/eslint-config-airbnb-base
'airbnb-base',
// 兼容typescript的airbnb规范
// https://github.com/iamturns/eslint-config-airbnb-typescript
'airbnb-typescript/base',
// typescript的eslint插件
// https://github.com/typescript-eslint/typescript-eslint/blob/master/docs/getting-started/linting/README.md
// https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
// 支持jest
'plugin:jest/recommended',
// 使用prettier格式化代码
// https://github.com/prettier/eslint-config-prettier#readme
'prettier',
// 整合typescript-eslint与prettier
// https://github.com/prettier/eslint-plugin-prettier
'plugin:prettier/recommended'
],
env: {
node: true,
jest: true,
},
ignorePatterns: [
// Ignore dotfiles
'node_modules/',
'dist/',
],
overrides: [
{
files: ['*.js?(x)', '*.ts?(x)', '*.json'],
},
],
rules: {
//
}
};

注意以下规则

eslint-plugin-unused-imports 用于自动删除未使用的导入

 'no-unused-vars': 0,
'@typescript-eslint/no-unused-vars': 0,
'unused-imports/no-unused-imports': 1,
'unused-imports/no-unused-vars': [
'error',
{
vars: 'all',
args: 'none',
ignoreRestSiblings: true,
},
]

import 插件,import/order 可以按照自己的需求配置

'import/order': [
'error',
{
pathGroups: [
{
pattern: '@/**',
group: 'external',
position: 'after',
},
],
alphabetize: { order: 'asc', caseInsensitive: false },
'newlines-between': 'always-and-inside-groups',
warnOnUnassignedImports: true,
},
],

Prettier配置

接下来配置.prettierrc文件,内容如下

module.exports = {
"singleQuote": true,
"trailingComma": "all",
"printWidth": 100,
"proseWrap": "never",
"endOfLine": "auto",
"semi": true,
"tabWidth": 4,
"overrides": [
{
"files": ".prettierrc",
"options": {
"parser": "json"
}
}
]
}

格式化命令

在package.json中添加以下脚本

{
"scripts": {
"dev": "pnpm start:dev",
"build": "tsc -p tsconfig.build.json",
"start:dev": "bun --watch src/main.ts",
"start": "node dist/main.js",
"start:debug": "bun --inspect src/main.ts",
"lint": "eslint \"{src,test}/**/*.ts\" --fix"
},
}

当我执行:pnpm lint之后: 会看到如下输出说明我的代码有格式问题:

(base) ➜  nodeapp pnpm lint

> nodeapp@1.0.0 lint /Users/jie.xu/coding/full-stack/3rclass/chapter1/nodeapp
> eslint "{src,test}/**/*.ts" --fix


/Users/jie.xu/coding/full-stack/3rclass/chapter1/nodeapp/src/main.ts
5:24 error 'request' is defined but never used @typescript-eslint/no-unused-vars
5:33 error 'reply' is defined but never used @typescript-eslint/no-unused-vars
11:5 warning Unexpected console statement no-console
14:3 warning Unexpected console statement no-console

4 problems (2 errors, 2 warnings)

 ELIFECYCLE  Command failed with exit code 1.

自动格式化

为了更方便的编写代码,我们配置一下vscode的自动格式化

安装 ESLint 插件和 Prettier 插件,可在 VSCode 插件中搜索并安装,或者使用如下命令安装

code --install-extension dbaeumer.vscode-eslint \
&& code --install-extension esbenp.prettier-vscode

按cmd+,(win或linux下为ctrl+,)打开偏好设置,选择“工作空间”,然后点红色箭头所指按钮创建.vscode/settings.json的配置文件

vscode 设置

把以下配置放进去,即可实现保存文件时自动格式化

{
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.fixAll.stylelint": "explicit"
},
"javascript.preferences.importModuleSpecifier": "project-relative",
"typescript.suggest.jsdoc.generateReturns": false,
"npm.packageManager": "pnpm"
}

忽略文件

一些文件是不需要格式化的,例如mardkown、图片、node_modules和dist中文件等等。

复制课程源码中的.eslintignore和.prettierignore文件到根目录即可

.eslintignore

/dist
/build
/node_modules
/back
/.docs/.obsidian
/.history
**/*.svg
**/*.md
**/*.svg
**/*.ejs
**/*.html
**/*.png
**/*.toml
.docusaurus
.dockerignore
.DS_Store
.eslintignore
docker
.editorconfig
Dockerfile*
.gitignore
.prettierignore
LICENSE
.eslintcache
*.lock
yarn-error.log

.prettierignore

/dist
/build
/node_modules
/back
/.docs/.obsidian
/.history
**/*.svg
**/*.md
**/*.svg
**/*.ejs
**/*.html
**/*.png
**/*.toml
.docusaurus
.dockerignore
.DS_Store
.eslintignore
docker
.editorconfig
Dockerfile*
.gitignore
.prettierignore
LICENSE
.eslintcache
*.lock
yarn-error.log

同时,把.gitignore复制到根目录,以防止node_modules、dist等文件或者目录提交到代码仓库

# Dependencies
node_modules
back
build

# Generated files
.docusaurus
.cache-loader

# Misc
.DS_Store
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*

Nestjs应用

上面,我们通过创建一个Fastify应用来简单地了解了以下TS+Node.js开始web后端应用开发的基本步骤。现在开始学习一下我们本课程后端部分的主力框架-Nestjs的应用创建步骤。总体上与fastify的过程差不多

安装 Nest CLI

pnpm add @nestjs/cli -g

创建项目,我们命名为 nestapp

nest new nestapp

We will scaffold your app in a few seconds..

? Which package manager would you ❤️ to use?
npm
yarn
❯ pnpm

进入到目录并用vscode打开编辑package.json以锁定eslint版本

cd nestapp && code $_

同样锁定eslint版本

{
// ...
"pnpm": {
"updateConfig": {
"ignoreDependencies": [
"eslint"
]
}
}
}

然后运行以下命令把所有依赖升级到最新版

pnpm up --latest