项目:react-travel | 版本:v1.2 | 生成日期:2026-10-06 | 依据:源码分析
package.json 的 dependencies 共 16 项、devDependencies 共 8 项,合计 24 个直接依赖——这是一个刻意保持克制的依赖面:没有状态管理之外的前端框架、没有 UI 工具集、没有测试框架、甚至没有日志库。对一份生产代码库做依赖逐个解析的价值在于三件事:其一,每个依赖都是一份供应链契约(升级带来什么、弃用损失什么、漏洞波及什么),不看使用位置就无法评估;其二,依赖清单是架构决策的化石层——《16-决策记录ADR》里的多数决策(双轨密码、Zustand、Redis 可选)都能在"哪个包在、哪个包不在"里找到物证;其三,健康度评估(§4)要回答"哪些依赖可以移除",这只有逐项 grep 过使用位置才能负责任地回答。
统计口径说明:下表"使用位置"列的每一条都经全仓 grep 验证(跳过 node_modules、.next、generated/ 生成物);"版本"列照抄 package.json 的 semver 范围(均为 ^ 前缀的次版本范围,lockfile pnpm-lock.yaml 锁定实际解析版本);engines 约束(node ≥ 20、pnpm ≥ 9)与 pnpm-workspace.yaml 的 allowBuilds 白名单(放行 @prisma/engines、prisma、sharp、@parcel/watcher 四个包的构建脚本)是两个"非依赖但决定依赖能否工作"的关键配置,见《14-配置与环境详解》§4。
| 依赖 | 版本 | 用途 | 使用位置(grep 证据) | 选型理由 | 替代方案与升级风险 |
|---|---|---|---|---|---|
| next | ^15.1.0 | 全栈框架(RSC/Route Handler/middleware/ISR/standalone) | 全仓基础;next.config.js;app/** 全部 | 迁移目标本身(ADR-01),SSR/RSC/SEO 一体化 | 升 Next 大版本需复查 webpack 自定义规则与 Turbopack 默认化(《14》§3) |
| react / react-dom | ^18.3.1 / ^18.3.1 | UI 运行时 | 全部组件;useIsomorphicLayoutEffect(providers)等 | Next 15 兼容最低稳定线;RSC + 客户端混合 | 升 React 19 需连带 @types 与 Next 版本联动 |
| antd | ^5.24.2 | 组件库(Form/Table/Tabs/Dropdown/AutoComplete/Result 等) | client/** 全部视图与组件、app/orderSuccess/page.tsx、loading.tsx 骨架 | CRA 时代即 antd v5,零迁移成本 | v6 升级涉 CSS-in-JS 模式变化;SSR 依赖 AntdRegistry 配套 |
| @ant-design/nextjs-registry | ^1.0.2 | antd v5 服务端样式抽取 | 仅 app/layout.tsx(AntdRegistry 包裹点) | antd 官方 App Router 集成方案,消除 FOUC | 与 antd 版本配套升级;替代品 @ant-design/cssinjs 手工抽取 |
| @ant-design/icons | ^5.6.1 | 图标(Heart/ShoppingCart/User/Star 等数百处) | client/components/**、client/views/**、app/orderSuccess/page.tsx 等 20+ 文件 | antd 官方图标库 | 独立升级低风险;tree-shaking 由构建器处理 |
| zustand | ^5.0.14 | 客户端状态(7 个 store + 派生 hook) | client/stores/* 全部、app/_components/AuthGuard.tsx、client/lib/http.ts(getState 读 token) | ADR-04:去 RTK 样板、selector 订阅、无 Provider | v4→v5 已过;替代:Jotai/Redux Toolkit(回流成本高) |
| @prisma/client | ^7.9.0 | Prisma 运行时(generated 代码的 runtime 依赖) | generated/prisma/client.ts 等生成物 import 其 runtime 子路径 | prisma-client 生成器的配套运行时 | 必须与 prisma CLI 版本严格同版(见 §3.4) |
| @prisma/adapter-pg | ^7.9.0 | 驱动适配器:Prisma 经 pg 协议直连 PostgreSQL | lib/prisma.ts、prisma/seed.ts、scripts/migrate-mysql-to-pg.ts | Prisma 7 driver adapter 新架构,取代 Rust 引擎 | 随 prisma 主版本联动升级 |
| axios | ^1.8.1 | 客户端 HTTP(拦截器附 Bearer) | client/lib/http.ts + 全部 7 个 store + ProductComments.tsx 等 | 沿用旧前端习惯;拦截器模型贴合"全局附 token" | 替代 fetch 需重写拦截器;风险低 |
| jsonwebtoken | ^9.0.2 | JWT 签发/校验(HS256) | lib/auth.ts(middleware.ts 中仅注释提及,不实际使用) | 与 Node 生态兼容性最好;同步 API 简单 | Edge Runtime 不可用——这正是 ADR-05 双层鉴权的成因 |
| ioredis | ^5.4.2 | Redis 客户端(token 缓存/注销) | 仅 lib/auth.ts | 命令式 API 直观;maxRetriesPerRequest 可调 | 可换 node-redis;REDIS_URL 未配置时该依赖完全不生效 |
| bcryptjs | ^3.0.3 | bcrypt 哈希(新账户 12 轮) | lib/password.ts、prisma/seed.ts(经 hashPassword) | 纯 JS 实现免原生编译,NAS/容器部署友好 | 性能低于原生 bcrypt;可换 bcrypt(需 node-gyp) |
| sanitize-html | ^2.17.7 | HTML 白名单净化/标签剥离 | 仅 lib/sanitize.ts(再被 lib/vm.ts 与各 Handler 引用) | 白名单模型成熟;支持属性/协议全禁 | 无显著风险;替代 DOMPurify 偏浏览器端 |
| dayjs | ^1.11.21 | 日期处理 + antd v5 官方配套 | 仅 app/providers.tsx(zh-cn locale 注册) | antd v5 DatePicker 的 peer 依赖 | 独立升级低风险 |
| dotenv | ^17.4.2 | .env 加载(CLI 场景) | prisma.config.ts、prisma/seed.ts、scripts/migrate-mysql-to-pg.ts | Prisma CLI 与 tsx 脚本不经 Next,需显式加载 | 仅脚本链路使用,风险极低 |
一项需要主动澄清的名单外事项:本系列任务候选清单中提到的 react-easy-crop,经全仓 grep(含 package.json、源码、pnpm-lock.yaml)确认不存在于当前依赖与代码中——它属于旧 CRA 时代可能引入过、迁移中被清理的包(或从未引入)⚠️ 待确认(无 git 历史可查证)。当前头像/图片裁剪功能不存在于站点功能清单(《00-项目总览》§2),该依赖缺席与功能缺席自洽,无需补装。
next 是唯一"既是框架又是运行时"的依赖:pnpm dev、pnpm build、pnpm start 三条脚本直接调它,生产部署甚至只需它的 standalone 产物(.next/standalone/server.js,《14-配置与环境详解》§6)。它在本项目承担六种角色:文件系统路由(app/**/page.tsx)、RSC 渲染与 ISR 缓存(revalidate 分级,ADR-06)、Route Handler 宿主(app/api/**/route.ts)、Edge middleware 宿主(middleware.ts,config.matcher = ["/api/:path*"])、请求管道(rewrites 在 middleware 之前执行,/auth/:path* → /api/auth/:path*)、以及构建期类型检查与预渲染(双门禁之二,《09-测试与质量保障》§2.2)。next.config.js 对它的六块定制(standalone 输出、disableStaticImages、remotePatterns 全放行、rewrites、webpack asset/resource、reactStrictMode)中五块为兼容层服务——《16-决策记录ADR》ADR-01 的决策直接写进了这个配置文件。升级视角:项目锁定在 ^15.1.0,Next 15 系内小版本升级风险集中在 params 变 Promise(项目已按 15 约定写法,app/api/orders/[id]/route.ts 等均 await params);跨大版本(16+)最大的复查点是 webpack 自定义规则(Turbopack 默认化后 config.module.rules.push 写法失效,图片 import 语义会当场破坏)与 middleware 的 Edge 语义变化。
antd ^5.24.2 是 UI 层唯一组件库,消费面覆盖 client/ 全部视图与组件、app/ 层的 loading.tsx 骨架(Spin)与 app/orderSuccess/page.tsx(Result)。它在本项目有两处架构级耦合:其一,v5 的 CSS-in-JS 需要 @ant-design/nextjs-registry 在服务端抽取样式——app/layout.tsx 的 <AntdRegistry> 是全站样式正确性的单点(漏掉它则 SSR HTML 无样式、hydration 后闪烁,见 ADR-12);其二,app/providers.tsx 的 ConfigProvider 同时注入 zhCN locale、dayjs locale(dayjs.locale("zh-cn"))与品牌主题 token(colorPrimary #0e7490 等),主题值与 client/styles/tokens.css 设计令牌同源——改品牌色要同时动两处。@ant-design/icons 的使用密度极高(Header 导航、TourCard 收藏红心、PaymentCard 图标等 20 余文件),受益于 Next 的 tree-shaking 无体积隐患。升级视角:v5 系内升级安全;v6 需评估 CSS-in-JS 运行时变化对 AntdRegistry 的连带影响;历史教训有先例——依赖生态的 CSS 加载在生产构建下失败(react-payment-inputs,已被 antd Form 替身取代),说明"antd 能力内自建"是本项目被验证过的降级路径。
zustand ^5.0.14 的消费面是 client/stores/ 全部 7 个 store、app/_components/AuthGuard.tsx(读 user store)、以及 client/lib/http.ts(useUserStore.getState().token 非-hook 读取,拦截器同步附 token)。它胜出的结构性理由有三:无 Provider 包裹(Providers 已被 AntdRegistry 与水合协议占据,再套 Redux Provider 只增嵌套);selector 订阅(useCartStore((s) => s.items) 让列表页几十张卡片只在自己数据变化时重渲染,《10-性能设计与优化》§6);store 内聚异步 action(signIn/checkout 这类"请求 + 状态迁移 + 持久化"的复合动作无需 thunk 中间件)。它的"手工持久化"模式(STORAGE_KEY 常量 + persist() 函数 + _hydrate() + hydrated 位)取代了 redux-persist,是《02-页面设计》§5 水合时序协议的载体。升级视角:v4→v5 的 breaking(移除默认导出等)项目已消化;该依赖 API 面积极小(create 一行),被弃用风险与迁移成本都是 24 项中最低的一档。
@prisma/client(运行时)、@prisma/adapter-pg(驱动适配器)与 devDependencies 中的 prisma(CLI/生成器)三者必须严格同版本(当前均 ^7.9.0)——Prisma 7 的新架构下,prisma-client 生成器产出的 generated/prisma/client.ts 显式 import @prisma/client/runtime/client 子路径,运行时与生成器版本错位会在类型或运行期直接报错;pnpm postinstall: prisma generate 依赖 pnpm-workspace.yaml#allowBuilds 对 @prisma/engines 的放行才能自动执行(《12-FAQ》坑 2 的根源)。@prisma/adapter-pg 是 Prisma 7 driver-adapter 架构的产物:lib/prisma.ts 把 PrismaPg({ connectionString: process.env.DATABASE_URL! }) 注入 PrismaClient,取代了旧版内置 Rust 引擎的网络层,连接行为即 Node pg 协议本身——这也让 dev 模式的 query/error/warn 三级日志成为排查数据问题的第一利器(《12-FAQ与故障排查》§4)。使用位置三处:lib/prisma.ts(应用单例)、prisma/seed.ts(种子自建实例)、scripts/migrate-mysql-to-pg.ts(一次性迁移脚本)。升级视角:Prisma 大版本升级必须三包联动 + 重新 generate + 复查 prisma.config.ts 配置入口格式,是 24 项中升级仪式感最重的一组。
这四个包分别支撑《08-安全与权限设计》的一条防线,且都是"单文件收敛"式使用。jsonwebtoken ^9.0.2 仅在 lib/auth.ts 出现(middleware.ts 中是注释提及):HS256 签发/校验、同步 API、payload { id, username };它不能在 Edge Runtime 运行,这一物理限制直接催生了 ADR-05 的双层鉴权结构。ioredis ^5.4.2 同样仅 lib/auth.ts:以 maxRetriesPerRequest: 1, connectTimeout: 5000 创建连接(宕机快速失败而非排队挂起),实现 token 缓存/比对/清除三函数;REDIS_URL 未配置时 getRedis() 返回 null,该依赖在无 Redis 部署中完全不生效——"可选基础设施"的典型实现。bcryptjs ^3.0.3 在 lib/password.ts(12 轮哈希与比对)与 prisma/seed.ts(种子账号哈希,经 hashPassword)使用,纯 JS 实现的取舍是 NAS/容器免编译,代价是比原生慢约 30%(12 轮约 100-300ms,恰好同时是 DUMMY 哈希时序对齐防御的物理基础)。sanitize-html ^2.17.7 只被 lib/sanitize.ts 引用,再经 stripHtml/sanitizeRichText 两函数辐射全部内容出口——allowedAttributes: {} 丢弃全部属性、allowedSchemes: [] 禁全部协议的极严配置见《08》§4。四件套的共同升级风险:jsonwebtoken v9 已修 alg 混淆漏洞,保持 ≥9 是安全底线;sanitize-html 需随安全公告及时升级(净化库自身的绕过漏洞会直接击穿防线)。
axios ^1.8.1 的存在理由是拦截器模型:client/lib/http.ts#installAuthInterceptor 在 app/providers.tsx 挂载时给默认实例装请求拦截器(installed 标志防 HMR 重复注册),此后全部客户端请求自动附 Authorization: Bearer——这层"全局副作用"用 fetch 要在每个调用点显式处理。消费面 10+ 文件(7 个 store、ProductComments、http.ts)。dayjs ^1.11.21 实际只有一处 import(app/providers.tsx 第 5-13 行:引入 + zh-cn locale 注册),它是 antd v5 日期组件的配套依赖,属于"为 peer 依赖而装"。dotenv ^17.4.2 服务于三条不走 Next 的执行链:prisma.config.ts 顶部 import "dotenv/config" 让 Prisma CLI 拿到 DATABASE_URL(这是 db push/seed 必须在项目根目录执行的原因)、prisma/seed.ts 与 scripts/migrate-mysql-to-pg.ts 两个 tsx 脚本的 .env 加载。三小件的升级风险都是"低"档:API 稳定、无 peer 纠缠。
| 依赖 | 版本 | 用途与使用位置 | 备注 |
|---|---|---|---|
| prisma | ^7.9.0 | CLI:generate/push/studio;package.json 四条脚本 + postinstall | 必须与 @prisma/client、adapter-pg 同版 |
| typescript | ^5.5.0 | 双门禁之一(pnpm exec tsc --noEmit);tsconfig.json strict 模式 | Next 构建内嵌类型检查复用同一份 tsconfig |
| @types/jsonwebtoken | ^9.0.7 | jsonwebtoken 的类型声明(该包无内建类型) | 随主包联动 |
| @types/node | ^20.14.0 | Node API 类型(crypto/pg 全局等) | 与 engines 的 node ≥ 20 对齐 |
| @types/pg | ^8.20.0 | pg 协议类型(adapter-pg 的底层类型引用) | 随 adapter-pg 联动 |
| @types/react / @types/react-dom | ^18.3.0 / ^18.3.0 | React 类型(strict 模式下全量生效) | 升 React 19 时同步大版本 |
| @types/sanitize-html | ^2.16.1 | sanitize-html 类型声明 | 随主包联动 |
devDependencies 的特征是"零工具链膨胀":没有 lint(ESLint/Prettier)、没有测试(Jest/Vitest/Playwright)、没有 git hooks(husky/lint-staged)。这与《09-测试与质量保障》§1 记录的"零自动化测试"现状互为证据——质量门禁只有 tsc 与 build 两道。若按《13-技术债务与演进建议》D7 补测,devDependencies 的第一批新增就是 Playwright(阶段一 E2E)与 Vitest(阶段二单测)。
直接依赖健康度总体为优:16 项 dependencies 全部有真实消费点(grep 可证),无一处于"装了没用"状态;版本范围全部是宽松次版本 ^,无过期锁死;无重复职能包(仅一个组件库、一个状态库、一个 HTTP 库)。逐项给出可操作结论:
pnpm remove 的依赖。最接近的候选项是 ioredis(若确定永不部署 Redis)与 dotenv(若把 seed/脚本改造为显式传参),但两者移除都会收窄部署弹性(ADR-05/ADR-11 的"可选增强"语义),不建议移除,标记为"保留"。dayjs 仅一处使用且只为 antd locale,若未来 antd 升级自带 locale 方案可随之移除;@prisma/adapter-pg + @prisma/client 的双包结构是 Prisma 7 新架构的既定形态,无可优化。console.error/warn 前缀约定承担全部观测(《12-FAQ》§4),多实例化前应引入结构化日志(pino 类);测试:见 §4 devDependencies;校验:参数校验靠手写 Number.isFinite/optionalStr 模式,若接口继续增长可评估 zod,但当前 39 个 Handler 的手写模式一致性良好,引入属可选项而非必要性。sanitize-html(安全库,漏洞即防线失效)与 next(服务端框架,历史上反代/中间件层 CVE 频出);其次是 jsonwebtoken 与 ioredis(均在鉴权路径上)。建议的巡检节奏:每月查一次安全公告,每季评估一次次版本升级,大版本升级绑定《13》§5 路线图的专门窗口。结论:这份依赖清单是"架构决策的物质化"——克制、全员在岗、每项都有可指认的源码消费点与文档化的取舍理由;它的脆弱点不在依赖本身,而在依赖之外(无 CI 锁定 lockfile 完整性、无 Dependabot/Renovate 类自动升级通道——已核实仓库无 .github/ 目录、无任何 CI 配置文件),补齐《13》D1 的 CI 后,把 §5 第 4 条的巡检节奏固化为流水线的 audit 步骤,依赖面就完成了从"个人纪律"到"机器保障"的闭环。