我的博客项目架构 - Tanstack Start与依赖注入实战
博客项目的开发过程中,作者学习了很多东西,尤其是对项目架构的理解,强调高内聚、低耦合的重要性。作者使用了Tanstack Start框架,利用其中间件系统实现了依赖注入,优雅地传递上下文。作者还介绍了三层架构、目录结构、类型系统的基石、Repo层、Service层、Middleware等,展示了如何利用中间件注入依赖,实现业务逻辑的封装和解耦。这种架构模式具有高内聚、低耦合、极致的开发体验等优点,适合长期维护和测试。
这个博客项目其实花了挺多时间开发的,从一开始的一知半解到现在学了很多东西。整个过程中边开发边学,遇到不懂的就问 AI,而这期间我收获最大的就是对项目架构的理解——讲究一个高内聚,低耦合。
而实现这一目标的关键手段,就是依赖注入 (Dependency Injection) 模式。这两个概念说起来其实是一个道理,带来的好处显而易见:代码可读性高、可维护性强、容易测试。
接下来,我就详细说说在这个博客项目中,我是如何利用新一代全栈框架 Tanstack Start 来实践这套架构的。
核心亮点:Tanstack Start 中间件
Tanstack Start 作为一个全栈框架,我觉得最亮眼的功能之一就是它的中间件 (Middleware) 系统。它不仅灵活,更是整个代码结构的中心。在我的架构中,我利用它作为依赖注入的载体,实现了优雅的上下文 (Context) 传递。
什么是依赖注入?
依赖注入说白了很简单:当你写一个函数时,把这个函数运行所依赖的东西(比如数据库连接、用户 Session)作为参数传进去,而不是在函数内部自己去创建或获取。我们将这些依赖参数统称为 Context。
例如,下面这个函数明确声明它需要一个 DbContext 才能运行:
这样做的好处是,如果你想测试这个函数,只需要 Mock 一下这个 context 依赖就行了,完全不需要启动真实的数据库。
架构概览:三层架构与目录结构
在深入代码之前,先看看整体的分层设计。主要分为三层:
API 层 (Interface Layer):定义 Server Functions(对外接口),负责参数校验、调用服务层。
Service 层 (Business Logic Layer):定义核心业务逻辑。
Repo 层 (Data Access Layer):负责原始数据的查询与持久化。
在目录结构上,我使用了 Feature-based 的组织方式,每个功能模块自包含这三层:
实战实现
1. 定义入口与基础 Context
一切的起点是请求的入口。Tanstack Start 提供了一个入口 Handler,这是定义基础 Context 的绝佳位置。由于我部署在 Cloudflare Workers 上,env 和 executionCtx 是全局通用的依赖,必须在这里注入。
src/server-entry.ts:
2. 类型系统的基石
为了开发时的类型提示和代码规范,我定义了一系列全局的 Context 类型。
src/global.d.ts:
3. Repo 层:数据访问
让我们从数据层写起。这里是一个获取文章列表的底层函数,它显式依赖 db: DB。
src/features/posts/data/posts.data.ts:
4. Service 层:业务逻辑
服务层负责编排业务流程。它接收 DbContext,并调用 Repo 层的数据方法。
src/features/posts/posts.service.ts:
这里的 GetPostsInput 类型复用了 Schema 定义,确保前后端类型一致:
src/features/posts/posts.schema.ts:
5. Middleware:注入的核心
这是最关键的一步。我们的 server-entry 只提供了 env,但 Service 层需要 db。我们使用中间件来“升级” Context。
src/lib/middlewares.ts:
6. API 层:闭环
最后,在 API 层(Server Function),我们将中间件、Validator 和 Handler 组合在一起。
API 定义:
进阶:扩展性展示
这套模式的扩展性非常强。比如,如果你需要处理用户鉴权,可以继续叠加中间件:
你甚至可以链式调用多个中间件,分别处理日志、鉴权、缓存等逻辑。
总结
通过这套架构,我们成功实现了:
高内聚:业务逻辑集中在 Service 层,数据访问集中在 Repo 层。
低耦合:各层之间通过显式的 Context 和参数依赖,不直接依赖全局状态或具体实现。
极致的开发体验:利用 Typescript 和 Zod 实现了端到端的类型安全,代码提示无敌。
这套“打法”虽然在初期搭建时稍微繁琐一点,但对于长期维护和测试来说,绝对是值得投入的。这不仅是代码的组织方式,更是思维方式的升级。