Route Forge — 设计思路

作者原始思路记录,用于项目演进追溯与决策参考。

1. 缘起

多年 Laravel + Vue 项目实战中,发现一个反复出现的痛点:

在 Laravel 项目里,我用过一套自创的方案: 前端按"分级"懒加载后端路由定义。后端注入路由元信息(名称 + 路径 + 方法),前端按需拉取并缓存。效果非常好——调用方只需要知道路由名,无需关心 URL 和方法。

2. 关键洞察

2.1 命名路由的本质是"意图而非位置"

调用 API 应该表达"我要做什么",而不是"我要去哪里"。

// 意图(好) api('entity.list', { entity: 'User' })
// 位置(差) axios.post('/app/User/data-list', query)

2.2 分级懒加载是大型 SPA 的刚需

把所有路由一次性导出,对于有数百个接口的后台系统:

按"级别"(level)分组、按需加载、按 level 隔离缓存,是更合理的方案。

2.3 方法应该和路由绑定

Laravel 路由定义里天然包含 HTTP 方法(GET/POST/PUT/DELETE),没理由让前端在调用时再指定一遍。

2.4 类型安全应贯穿全链路

路由名 → 路径参数 → 响应类型,整条链路都该有 TS 类型保护。任何一个环节 any 掉都会让系统变得脆弱。

3. 现有方案的不足

命名路由一次性导出方案

其他方案

4. Route Forge 的核心定位

"给 Laravel + 前端 SPA 项目提供一套完整、可分级、类型安全的命名路由解决方案。"

补齐现有命名路由方案缺失的能力:

维度 Route Forge
命名路由导出
类型生成
分级懒加载
并发控制
请求封装
拦截器(登录态/Token 由用户控制)
缓存隔离
请求流程优化(校验前置 + 错误恢复)
摘要端点(自动发现)
middleware_match(DNF)
配置分级覆盖(后端权威)
自定义分类 完全可定制

5. 设计原则

  1. 约定优于配置:零配置也能跑,但所有约定都可通过配置覆盖。
  2. 默认宽松,按需严格strict_mode 默认关闭,降低接入门槛;需要精确校验的项目显式开启,前后端 strict_mode 以后端为权威值。
  3. 类型安全全链路:路由名 → 参数 → 响应全程可推导。
  4. 零侵入:只通过 Laravel 的扩展点(macro、ServiceProvider)工作,不修改框架核心。
  5. 渐进式复杂度:简单项目用默认值;复杂项目才需要写配置。
  6. 可独立测试:每个组件都能脱离完整应用单独测试。

6. 关键技术决策

6.1 为什么不用 OpenAPI

6.2 HTTP 客户端适配策略

早期方案考虑过用 ofetch 作为默认 HTTP 客户端(API 现代、类型好、体积小),但实际落地时发现三个问题:

  1. 存量项目已有 axios:强制引入第二个 HTTP 库会造成包体积浪费和拦截器配置分裂;
  2. 零依赖新项目:不想装任何 HTTP 库的轻量项目,ofetch 仍然是一个外部依赖;
  3. 统一拦截器行为:不同 adapter 的拦截器语义不一致,用户切换 adapter 时行为可能变化。

最终方案:

6.3 为什么拆成两个仓库

早期采用 monorepo(pnpm workspace + turborepo)统一管理 Laravel 包、TS core、Vue 插件三个包。随着项目演进,决定拆分为两个独立仓库:

拆分理由:

拆分后的协作纪律:

6.4 为什么 level 不固定

6.5 Blade 注入的取舍:从「统一摘要端点」到「可选首页加速」

早期(见旧版本文档)曾考虑并否决了 Blade 注入:担心 ① Vue/SPA 独立部署 HTML 不经 Laravel、② Vite dev 无 Blade 渲染、③ 多一套机制增加条件判断。这三条至今成立——所以 Blade 注入不能成为唯一路径

后来把它重新引入,但定位变了:不是"替换摘要端点",而是投递同一份 SummaryResponse 的可选加速通道

最终口径:摘要端点仍是配置权威与默认来源;Blade 内嵌是其上叠加的可选首页加速(级联:内嵌 > createRouteForge({summary}) > 网络),见 SPEC §3.1.6 / §3.1.8 / §4.1.1。

6.6 为什么类型由后端 Artisan 命令生成

早期考虑过由前端 CLI(请求摘要端点)生成 TS 类型,最终改为后端 route:forge:types Artisan 命令,理由:

  1. 路由定义是后端数据:类型必须从唯一真相源(Route::getRoutes())生成,手写或旁路生成都会与路由表脱节;
  2. 离线可用:直接从内存路由注册表读取,不需要启动 HTTP 服务;
  3. CI 友好:PHP 构建阶段无需 Node 环境即可产出类型文件。

7. 风险与权衡

风险 缓解策略
Laravel 大版本升级导致 API 变动 抽象一层适配器;CI 跑 Laravel 9/10/11 三矩阵
开源项目维护疲劳 设定清晰的 Roadmap;拒绝超出定位的 feature request
TS 类型推导在某些边界情况下失败 提供 escape hatch(api<any>(...)),但不鼓励
fallback_level=null 暴露未标记路由 文档建议生产环境开启 strict_mode=true 或显式标记所有路由
levels 数组顺序影响多命中结果 文档明确"后定义覆盖前定义"语义;测试矩阵覆盖多命中场景

8. 长期愿景

9. 个人投入预期