项目地址
- 在线预览:frontend-ai-assistant-two.vercel.app/
- GitHub 源码:github.com/hewq/dify-c…
说明:当前在线版本部署在 Vercel,国内网络访问可能不稳定。如果打不开,可以直接查看 GitHub 源码并在本地启动。
前言
上一篇我们完成了服务端工程化重构,把原本臃肿的 server/index.ts 拆成了更清晰的结构:
server/
config/
env.ts
routes/
chat.ts
services/
dify.ts
types/
dify.ts
utils/
errors.ts
index.ts
到这里,项目已经不再只是一个能跑的 AI Demo。
它已经具备了比较完整的功能和结构:
Dify RAG 知识库
DeepSeek 模型
Vite React 前端
Express BFF
SSE 流式输出
Markdown 渲染
引用来源展示
多会话管理
停止生成
前端 Hook 拆分
服务端分层
但一个项目想继续长期维护,还需要一件很重要的事:
质量门禁。
也就是在开发、提交、构建之前,自动帮我们发现一些低级问题。
这一篇我们就给项目加上:
ESLint
Prettier
TypeScript strict
Husky
lint-staged
目标是让个人项目也具备团队项目的基础规范。
为什么个人项目也需要质量门禁?
很多人觉得个人项目没必要配这些东西。
一开始确实可以不配。
但当项目逐渐变复杂后,没有质量门禁会出现很多问题:
1. 代码风格不统一
2. 有些文件单引号,有些文件双引号
3. 有些地方加分号,有些地方不加
4. 未使用变量没人发现
5. 类型错误到构建时才暴露
6. any 越写越多
7. 提交到 GitHub 后才发现 lint 不通过
8. README 里写的启动方式和实际不一致
尤其是这个项目已经有:
前端 React 代码
服务端 Express 代码
TypeScript 类型
环境变量
流式请求
localStorage 状态
代码面越来越广,越早加质量门禁,后面越省心。
本篇目标
这一篇完成后,项目会支持:
1. Prettier 统一代码格式
2. ESLint 检查 TypeScript / React 常见问题
3. TypeScript 开启严格检查
4. npm run check 一键检查项目质量
5. Git commit 前自动格式化和检查
6. README 增加质量保障说明
最终我们希望常用命令变成:
npm run lint
npm run format
npm run typecheck
npm run check
并且提交前自动执行:
lint-staged
TypeScript typecheck
第一步:安装依赖
在项目根目录执行:
npm install -D prettier eslint-config-prettier lint-staged husky
如果你的 Vite 项目本身已经带 ESLint,这一步不用重复安装 ESLint。
如果没有,再补:
npm install -D eslint typescript-eslint eslint-plugin-react-hooks eslint-plugin-react-refresh globals
几个依赖的作用:
prettier:代码格式化
eslint:代码质量检查
eslint-config-prettier:关闭和 Prettier 冲突的 ESLint 规则
lint-staged:只检查本次提交暂存区文件
husky:Git hooks 工具
typescript-eslint:让 ESLint 支持 TypeScript
eslint-plugin-react-hooks:检查 React Hooks 使用规则
eslint-plugin-react-refresh:Vite React 常用规则
globals:提供 browser / node 全局变量定义
第二步:配置 Prettier
在项目根目录新建:
.prettierrc
写入:
{
"semi": false,
"singleQuote": true,
"printWidth": 80,
"trailingComma": "es5"
}
这里我选择:
不加分号
使用单引号
每行 80 字符
尾随逗号使用 es5 兼容风格
这不是唯一标准,团队可以按自己的习惯调整。
关键是:
项目里要有统一标准,而不是每个人按自己的喜好写。
再新建:
.prettierignore
写入:
dist
node_modules
coverage
.env
这些文件不需要格式化。
第三步:配置 ESLint
Vite React TS 新项目通常会生成:
eslint.config.js
我们可以调整成支持前端和服务端两套环境。
因为当前项目里既有:
src/**/*.ts / src/**/*.tsx
也有:
server/**/*.ts
前端需要 browser globals,服务端需要 node globals。
参考配置:
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
import prettier from 'eslint-config-prettier'
export default tseslint.config(
{ ignores: ['dist', 'node_modules'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['src/**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
'@typescript-eslint/no-explicit-any': 'warn',
},
},
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['server/**/*.ts'],
languageOptions: {
ecmaVersion: 2022,
globals: globals.node,
},
rules: {
'@typescript-eslint/no-explicit-any': 'warn',
},
},
prettier
)
这里有几个点:
1. src 使用 browser globals
2. server 使用 node globals
3. React Hooks 使用官方推荐规则
4. no-explicit-any 暂时设为 warn,而不是 error
5. 最后加 prettier,避免 ESLint 和 Prettier 冲突
为什么 no-explicit-any 先设为 warn?
项目早期如果直接把所有 any 都禁掉,可能会让开发体验变差。
尤其是接外部 API 时,比如 Dify 的返回结构不一定完全稳定。
所以我建议先设为:
'@typescript-eslint/no-explicit-any': 'warn'
这样它会提醒你,但不会阻断开发。
等项目类型逐渐完善后,再升级为:
'@typescript-eslint/no-explicit-any': 'error'
质量门禁也要逐步提高,不一定一开始就拉满。
第四步:修改 package.json scripts
打开 package.json,补充这些命令:
{
"scripts": {
"dev": "vite",
"server": "tsx watch server/index.ts",
"dev:all": "concurrently "npm run server" "npm run dev"",
"build": "tsc -b && vite build",
"start": "tsx server/index.ts",
"preview": "vite preview",
"lint": "eslint .",
"format": "prettier . --write",
"format:check": "prettier . --check",
"typecheck": "tsc -b --noEmit",
"check": "npm run typecheck && npm run lint && npm run format:check"
}
}
几个命令说明:
npm run lint 运行 ESLint
npm run format 自动格式化
npm run format:check 检查格式是否正确,但不修改文件
npm run typecheck 只做 TypeScript 类型检查,不输出构建产物
npm run check 一键执行 typecheck + lint + format:check
以后每次提交前,可以先跑:
npm run check
第五步:开启 TypeScript 严格检查
打开:
tsconfig.app.json
确认有这些配置:
{
"compilerOptions": {
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
}
}
如果服务端有单独的:
tsconfig.node.json
也建议加:
{
"compilerOptions": {
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true
}
}
开启这些后,可能会暴露一些问题,比如:
定义了变量但没用
函数参数没用
某些值可能是 undefined
类型推断不够明确
这些报错不是麻烦,而是在帮我们提前发现潜在问题。
第六步:配置 lint-staged
在 package.json 里增加:
{
"lint-staged": {
"*.{ts,tsx,js,jsx,json,css,md}": [
"prettier --write"
],
"*.{ts,tsx}": [
"eslint --fix"
]
}
}
lint-staged 只处理 Git 暂存区里的文件。
这比每次提交都全量格式化整个项目更快。
它会在提交前自动:
格式化本次提交的文件
自动修复 ESLint 能修的问题
第七步:配置 Husky
执行:
npx husky init
它会生成:
.husky/pre-commit
把里面内容改成:
npx lint-staged
npm run typecheck
这样每次执行:
git commit
之前都会自动执行:
1. lint-staged
2. TypeScript 类型检查
如果检查不通过,提交会被阻止。
这就是提交前质量门禁。
第八步:跑一次全量格式化和检查
执行:
npm run format
npm run check
第一次跑时,可能会出现一些报错。
这是正常的。
下面列几个常见问题。
常见问题 1:未使用变量
比如:
'activeSession' is assigned a value but never used
解决方式:
没用就删掉
确实要用就补上逻辑
不要为了消除报错写一些无意义代码。
常见问题 2:catch error 是 unknown
TypeScript strict 下,catch (error) 默认是 unknown。
不要直接:
console.log(error.message)
应该写:
const message = error instanceof Error ? error.message : 'Unknown error'
这也是我们之前在服务端加 getErrorMessage 的原因。
常见问题 3:Node 类型缺失
如果服务端提示:
Cannot find name 'process'
或者:
Cannot find module 'path'
安装:
npm install -D @types/node
并确认 server 相关 tsconfig 能识别 Node 类型。
常见问题 4:格式检查不通过
如果 npm run format:check 报错,说明有文件格式不符合 Prettier。
直接执行:
npm run format
再重新:
npm run check
第九步:测试 pre-commit
随便改一个文件,然后执行:
git add .
git commit -m "chore: add quality gate"
如果配置成功,提交前会自动执行:
npx lint-staged
npm run typecheck
如果有错误,提交会失败。
修复后重新提交即可。
第十步:更新 README
在 README 中加一节:
## 代码质量
项目配置了基础质量保障:
- TypeScript strict mode
- ESLint
- Prettier
- Husky
- lint-staged
- pre-commit typecheck
常用命令:
```bash
npm run lint
npm run format
npm run typecheck
npm run check
README 不只是给别人看的,也是给未来的自己看的。
等几个月后再回到这个项目,清晰的命令说明会很有帮助。
---
## 当前质量门禁覆盖了什么?
现在项目有几层保障:
### 1. 格式层
由 Prettier 负责:
```text
缩进
换行
引号
尾随逗号
代码宽度
2. 代码规范层
由 ESLint 负责:
未使用变量
React Hooks 规则
不推荐写法
部分 TypeScript 问题
3. 类型层
由 TypeScript 负责:
类型不匹配
可能 undefined
错误参数
返回值不一致
4. 提交流程层
由 Husky + lint-staged 负责:
提交前自动格式化
提交前自动修复 lint
提交前跑 typecheck
这几层组合起来,就是一个基础质量门禁。
这一步的工程价值
这一篇没有新增任何用户功能。
但是它对项目长期维护非常重要。
它的价值是:
1. 降低低级错误出现概率
2. 保证代码风格统一
3. 提交前发现类型问题
4. 让项目更像团队工程
5. 方便后续多人协作
6. 让简历项目更有工程含金量
很多简历项目只展示功能,但代码质量不一定好。
如果你能在 README 里明确写出:
TypeScript strict
ESLint
Prettier
Husky
lint-staged
这会比单纯写“实现了 AI 聊天”更能体现工程意识。
当前版本还有哪些不足?
现在项目已经有了比较完整的前后端工程结构和质量门禁。
接下来就会遇到部署问题。
我们前面尝试过几种方案:
Vercel
Render
Railway
国内轻量服务器
每种都有优缺点。
比如:
Vercel:免费方便,但国内访问不稳定,Express streaming 要改造
Render:适合 Node 服务,但可能要求绑卡
Railway:适合部署完整 Express 服务,但不是永久免费
国内轻量服务器:国内访问稳定,但需要购买和运维
下一篇我们专门写部署方案选择。
不是马上教某一种平台怎么部署,而是先分析:
这个项目到底适合部署在哪里?
本篇总结
这一篇我们给项目加上了基础质量门禁。
主要完成:
1. 安装 Prettier / ESLint / Husky / lint-staged
2. 配置 .prettierrc
3. 配置 .prettierignore
4. 配置 eslint.config.js
5. 区分前端 browser 环境和服务端 node 环境
6. 增加 lint / format / typecheck / check 命令
7. 开启 TypeScript strict 相关检查
8. 配置 lint-staged
9. 配置 Husky pre-commit
10. 更新 README 质量保障说明
到这里,项目已经具备了正式项目的基础工程质量。
下一篇我们聊部署:
Vercel、Railway、Render、国内轻量服务器怎么选?