全栈开发框架skrun:基于Node.js与Fastify的快速应用构建指南
1. 项目概述一个面向开发者的全栈应用快速开发框架最近在和一些独立开发者朋友聊天时大家普遍提到一个痛点从零开始搭建一个具备现代技术栈、良好架构和基础业务功能的Web应用前期的“基建”工作实在太耗时了。每次新项目启动都要重复配置路由、状态管理、数据库ORM、API接口规范、用户认证授权甚至部署脚本。这个过程快则一两天慢则一周宝贵的创造力和时间都消耗在了重复劳动上。正是在这种背景下我注意到了 GitHub 上的一个开源项目skrun-dev/skrun。乍一看这个名字可能会联想到“快速运行”或者某种脚本工具但深入探究后我发现它的定位远不止于此。skrun本质上是一个为开发者尤其是全栈和独立开发者量身打造的全栈应用快速开发框架与工具集。它的核心目标非常明确通过提供一套开箱即用、高度集成且可扩展的脚手架和最佳实践将开发者从繁琐的通用配置中解放出来让他们能专注于核心业务逻辑的创新与实现。简单来说如果你要开发一个现代化的Web应用无论是SaaS产品、内部工具还是个人项目skrun 希望成为你的“项目起点加速器”。它不是一个单一的库而是一个预设的技术栈组合与项目生成器。它帮你做好了技术选型、基础架构搭建和通用模块集成你拿到手的就是一个五脏俱全、可以直接在此基础上进行业务开发的项目骨架。这个项目适合谁呢我认为主要面向以下几类开发者独立开发者/创业者时间就是生命线需要快速验证产品想法MVP没有太多精力去反复搭建技术底座。全栈工程师经常需要负责从前端到后端的完整项目希望有一套熟悉、可靠且高效的标准化起点。中小型团队需要统一团队的技术栈和项目结构降低新成员上手成本提升项目初始化的速度和一致性。学习现代全栈技术的开发者想通过一个完整的、生产级别的项目范例来学习前后端如何协同、认证授权如何实现、项目如何组织等实战知识。接下来我将结合对 skrun 项目源码和设计思路的剖析以及我个人在类似场景下的实践经验为你深度拆解这个框架的核心价值、技术实现、使用心法以及如何让它真正为你所用。2. 核心架构与技术栈选型解析要理解 skrun 的价值首先得看清它肚子里装的是什么“货”。一个框架的选型直接决定了它的能力边界、开发体验和未来的可维护性。skrun 的选型体现了明显的“务实”与“现代”倾向旨在平衡开发效率、性能和学习成本。2.1 后端技术栈Node.js 与 Fastify 的效能组合skrun 的后端基石是Node.js和Fastify。这个选择非常值得玩味。为什么是 Node.js对于全栈快速开发框架而言Node.js 几乎是“标配”选择。其核心优势在于JavaScript/TypeScript 的统一语言栈。开发者可以用同一种语言编写前端和后端逻辑这极大地降低了上下文切换成本简化了全栈开发的认知负荷。更重要的是Node.js 拥有空前繁荣的生态npm任何你能想到的功能几乎都有现成的、经过考验的包可用这为快速集成各种功能模块提供了坚实基础。为什么是 Fastify而不是更流行的 Express 或 Koa这是 skrun 一个颇具远见的选择。Express 固然是元老生态庞大但其架构相对陈旧性能并非其最强项。Koa 更现代、更优雅但在中间件生态和易用性上略逊于 Express。Fastify 则是一个后起之秀它被设计时就以极高的性能和低开销为核心目标。官方基准测试显示Fastify 的请求吞吐量远超 Express 和 Koa。对于追求响应速度和资源效率的应用尤其是云原生、Serverless 环境这个优势是实实在在的。此外Fastify 内置了对 JSON Schema 的深度支持这使得输入输出验证变得异常简单和高效。你只需要定义好数据的“形状”SchemaFastify 会自动帮你完成验证、序列化甚至生成 OpenAPISwagger文档。这对于构建健壮、文档清晰的 API 至关重要。skrun 利用这一点为生成结构良好、自文档化的 API 打下了基础。实操心得从 Express 迁移到 Fastify 初期可能会有点不习惯尤其是插件系统和生命周期钩子。但一旦熟悉你会爱上它的性能和开发体验。skrun 帮你做好了这层封装让你可以直接享受 Fastify 的好处而无需从零配置。2.2 数据库层Prisma ORM 的声明式数据建模数据库操作是后端开发的重头戏。skrun 选择了Prisma作为其 ORM对象关系映射工具这是一个非常现代且开发者友好的选择。Prisma 的核心是一个schema.prisma文件你用一种直观的领域特定语言DSL来声明你的数据模型。例如model User { id String id default(cuid()) email String unique name String? posts Post[] createdAt DateTime default(now()) } model Post { id String id default(cuid()) title String content String? published Boolean default(false) author User relation(fields: [authorId], references: [id]) authorId String }然后运行prisma generate命令Prisma 会根据这个 Schema 文件为你生成类型安全的数据库客户端代码。这意味着你在 TypeScript 中调用prisma.user.findUnique(...)时编辑器能提供完美的自动补全并且会在编译时检查查询的正确性极大减少了运行时错误。skrun 集成 Prisma 带来的好处类型安全数据库访问从数据库到应用代码全程类型安全这是大型项目维护的福音。数据库迁移管理Prisma Migrate 提供了强大的数据库版本控制和迁移工具prisma migrate dev一键生成并应用迁移文件让数据库 schema 的演进变得可控。开箱即用的多数据库支持Prisma 支持 PostgreSQL, MySQL, SQLite, SQL Server 等。skrun 通常预设 SQLite用于快速原型和 PostgreSQL用于生产你可以根据项目需要轻松切换。清晰的抽象层Prisma 的查询 API 既强大又直观避免了编写原始 SQL 的繁琐和潜在的安全风险如 SQL 注入。2.3 前端技术栈React 生态的现代组合在前端方面skrun 拥抱了最主流的React生态。但它不是简单堆砌库而是做了精心整合。构建工具Vite。这取代了传统的 Webpack。Vite 的启动速度和热更新HMR体验是革命性的尤其在开发阶段能极大提升幸福感。skrun 使用 Vite 意味着你项目的前端部分拥有极致的开发效率。语言TypeScript。与后端保持一致确保全栈类型安全。这减少了前后端接口约定出错的概率。路由React Router。行业标准处理单页应用SPA路由的可靠选择。状态管理这里 skrun 可能提供选项或采用轻量级方案如 Zustand 或 Context API useReducer而不是强制使用 Redux。这符合现代 React 开发“按需引入复杂度”的理念。对于大多数由 skrun 生成的中小型应用轻量级状态管理已足够。样式方案可能会集成像Tailwind CSS这样的实用优先的 CSS 框架。Tailwind 的“原子化”理念能让你快速构建 UI而无需在 HTML 和 CSS 文件间来回切换非常适合快速开发。API 客户端很可能会集成TanStack Query原 React Query或类似的库用于管理服务器状态获取、缓存、同步、更新。这让你能优雅地处理数据获取而无需手动管理 loading 状态和缓存逻辑。前后端通信skrun 通常会预设基于RESTful或tRPC的通信模式。如果采用 tRPC则能实现从后端到前端的端到端类型安全调用 API 就像调用本地函数一样体验非常流畅。2.4 身份认证与授权开箱即用的安全基石用户系统是绝大多数应用的核心。从头实现一个安全、可靠的认证Authentication和授权Authorization系统非常复杂且容易出错。skrun 的另一个巨大价值就是内置了成熟的认证方案。它很可能集成了像NextAuth.js如果采用 Next.js或Passport.js策略在 Fastify 中并预设了以下功能多种登录方式邮箱/密码、OAuthGoogle, GitHub, 微信等。会话管理安全的 Cookie 或 JWTJSON Web Token管理。数据库集成用户模型User Model已与 Prisma Schema 集成。受保护的路由/API提供了高阶组件HOC或装饰器让你能轻松标记哪些页面或接口需要登录才能访问。这意味着你运行skrun create my-app后就已经拥有了一个可以注册、登录、注销的完整用户系统省去了数天甚至数周的安全开发工作。2.5 开发与部署工具链一个现代项目离不开完善的工具链。skrun 在这方面也考虑周全代码质量预置 ESLint 和 Prettier 配置统一代码风格。Git 钩子可能通过 Husky 设置 pre-commit 钩子在提交前自动运行代码检查和格式化。环境变量管理使用.env文件并区分开发、测试、生产环境。Docker 支持提供Dockerfile和docker-compose.yml方便本地容器化开发和一键部署到云平台。部署配置可能提供针对 Vercel, Railway, Render 或常规 Linux 服务器的部署脚本或指南。通过这一套精心挑选和整合的技术栈skrun 为你构建了一个坚固、高效且现代化的“开发底盘”。你不需要再争论该选什么技术也不需要花费时间让这些技术协同工作——skrun 已经帮你完成了这项艰巨的集成工作。3. 从零到一使用 skrun 快速启动你的项目了解了 skrun 的“内力”之后我们来实战一下看看如何用它快速生成一个可运行的全栈应用。这个过程通常极其简单这也是框架设计的初衷。3.1 环境准备与项目生成首先确保你的本地开发环境已经就绪Node.js建议安装最新的 LTS 版本如 18.x, 20.x。你可以使用nvmNode Version Manager来管理多个版本。包管理器npm 或 yarn 或 pnpm。skrun 的文档会指明其偏好通常 pnpm 因其速度和磁盘空间效率而受到推荐。数据库开发环境可以使用轻量级的 SQLite无需额外安装。如果想用 PostgreSQL则需要本地安装或使用 Docker 运行。接下来就是最激动人心的时刻——创建项目。假设 skrun 提供了一个 CLI 工具这是这类框架的常见做法命令可能类似于# 使用 npx 直接运行最常见的方式 npx create-skrunlatest my-awesome-app # 或者如果提供了全局安装的 CLI npm install -g skrun/cli skrun create my-awesome-app运行命令后CLI 工具会交互式地询问你一些选项例如项目名称my-awesome-app数据库类型SQLite (开发) / PostgreSQL (生产)认证方式仅邮箱密码 / 包含 GitHub OAuth / 包含 Google OAuth前端框架React (Vite) / Next.js (如果支持)UI 库None / Tailwind CSS / 其他部署预设None / Vercel / Docker你根据提示做出选择后CLI 就会开始“施法”下载模板、安装所有依赖包这可能会花几分钟因为依赖较多、根据你的选择配置项目文件、初始化 Git 仓库、甚至创建初始的数据库迁移。3.2 生成项目的目录结构解析命令执行完毕进入项目目录cd my-awesome-app你会看到一个结构清晰、约定俗成的目录树my-awesome-app/ ├── .github/ # GitHub Actions 工作流配置如果包含 ├── .vscode/ # VSCode 推荐配置如调试、扩展 ├── backend/ # 后端服务代码 │ ├── src/ │ │ ├── index.ts # Fastify 应用入口 │ │ ├── plugins/ # Fastify 插件如认证、数据库 │ │ ├── routes/ # API 路由定义 │ │ │ └── v1/ # API 版本 v1 │ │ │ ├── auth/ # 认证相关路由 │ │ │ └── posts/ # 示例业务路由 │ │ └── lib/ # 工具函数、配置 │ ├── prisma/ │ │ ├── schema.prisma # Prisma 数据模型定义 │ │ └── migrations/ # 数据库迁移文件 │ ├── Dockerfile │ └── package.json ├── frontend/ # 前端应用代码 │ ├── src/ │ │ ├── main.tsx # 应用入口 │ │ ├── App.tsx # 根组件 │ │ ├── pages/ # 页面组件 │ │ │ ├── Login.tsx │ │ │ ├── Dashboard.tsx │ │ │ └── ... │ │ ├── components/ # 可复用UI组件 │ │ ├── hooks/ # 自定义 React Hooks │ │ ├── lib/ # 前端工具、API 客户端配置 │ │ └── styles/ # 全局样式 │ ├── index.html │ ├── vite.config.ts │ └── package.json ├── packages/ # 可选Monorepo 共享包 │ └── shared/ # 前后端共享的类型定义、工具 ├── docker-compose.yml # 本地多服务编排 ├── .env.example # 环境变量示例 ├── .gitignore ├── package.json (workspace root) # 如果使用 monorepo └── README.md这个结构不是随意的它遵循了当前全栈项目的最佳组织实践分离关注点同时便于协作。3.3 首次运行与初体验现在让我们点燃引擎。根据 README.md 的指引通常只需要几步# 1. 复制环境变量文件并填入你的密钥如数据库连接串、OAuth密钥 cp .env.example .env # 编辑 .env 文件填入必要配置 # 2. 安装所有依赖如果 CLI 没自动安装 pnpm install # 或 npm install # 3. 生成 Prisma 客户端并运行数据库迁移 cd backend pnpm prisma generate pnpm prisma migrate dev --name init # 4. 启动开发服务器 # 方式A分别启动前后端两个终端 # 终端1启动后端 cd backend pnpm dev # 终端2启动前端 cd frontend pnpm dev # 方式B使用根目录的脚本同时启动如果项目配置了 pnpm dev如果一切顺利打开浏览器访问http://localhost:5173Vite 前端默认端口你应该会看到一个正在运行的应用它可能包含一个简单的首页、一个可以点击的登录/注册链接。点击注册填写表单一个用户账号就被创建并存入数据库了。整个过程你没有写一行后端认证代码或前端表单处理逻辑。注意事项首次运行最常见的坑是.env 文件配置错误。务必仔细检查DATABASE_URL是否正确指向了你的数据库本地 SQLite 文件路径或 PostgreSQL 连接串。另外如果使用了 OAuth需要提前去对应的开发者平台如 Google Cloud Console, GitHub Developer Settings创建应用获取CLIENT_ID和CLIENT_SECRET并填入.env文件否则第三方登录会失败。4. 核心功能模块深度定制与扩展skrun 提供的“脚手架”只是起点真正的价值在于你如何在此基础上快速构建自己的业务。我们来深入几个核心模块看看如何进行定制和开发。4.1 数据模型定义与业务逻辑开发假设我们要为一个博客平台添加“文章评论”功能。我们需要扩展数据模型打开backend/prisma/schema.prisma添加Comment模型。model Comment { id String id default(cuid()) content String post Post relation(fields: [postId], references: [id]) postId String author User relation(fields: [authorId], references: [id]) authorId String createdAt DateTime default(now()) updatedAt DateTime updatedAt }生成数据库迁移cd backend pnpm prisma migrate dev --name add_comment_model这条命令会a) 根据 schema 变化生成迁移文件b) 对开发数据库应用该迁移c) 重新生成 Prisma Client 类型定义。创建 API 路由在backend/src/routes/v1/下新建comments.ts。import { FastifyInstance } from fastify; import { prisma } from ../../lib/prisma; // skrun 预设的 Prisma 实例 export default async function commentRoutes(fastify: FastifyInstance) { // 获取某篇文章的评论 fastify.get(/posts/:postId/comments, async (request, reply) { const { postId } request.params as { postId: string }; const comments await prisma.comment.findMany({ where: { postId }, include: { author: { select: { id: name, email: true } } }, // 关联查询作者信息 orderBy: { createdAt: desc }, }); return comments; }); // 创建评论需要认证 fastify.post(/posts/:postId/comments, { onRequest: [fastify.authenticate], // 使用 skrun 内置的认证钩子 }, async (request, reply) { const { postId } request.params as { postId: string }; const { content } request.body as { content: string }; const userId request.user.id; // 从认证钩子中获取当前用户 const comment await prisma.comment.create({ data: { content, postId, authorId: userId, }, }); return comment; }); }注册路由在backend/src/index.ts或类似的主路由注册文件中引入并注册这个新的路由模块。前端调用在前端项目中使用配置好的 API 客户端如 axios 或 tRPC 客户端调用这些新接口并在对应页面如文章详情页渲染评论列表和发表框。整个过程从数据层到 API 层再到前端集成脉络非常清晰。Prisma 提供了类型安全的数据库操作Fastify 提供了高效的路由和验证skrun 预设的认证钩子让你轻松保护接口。你只需要关注最核心的业务逻辑findMany,create以及如何呈现数据。4.2 用户认证与权限管理的深入使用skrun 内置的认证系统通常已经处理了登录态Session/JWT的创建和验证。但在实际业务中我们经常需要更细粒度的权限控制Authorization。例如用户只能编辑或删除自己发布的文章。这通常需要在业务逻辑层进行判断。skrun 的认证钩子如fastify.authenticate会将用户信息从 JWT 或 Session 中解析出挂载到request对象上如request.user。你可以在路由处理函数中利用这个信息// 更新文章路由 fastify.put(/posts/:id, { onRequest: [fastify.authenticate], }, async (request, reply) { const { id } request.params as { id: string }; const updates request.body as PartialPost; const userId request.user.id; // 1. 先查找文章确认存在且作者是当前用户 const existingPost await prisma.post.findUnique({ where: { id }, select: { authorId: true }, // 只查询作者ID }); if (!existingPost) { throw new Error(Post not found); } if (existingPost.authorId ! userId) { // 返回 403 Forbidden 错误 reply.code(403).send({ error: You are not authorized to edit this post }); return; } // 2. 通过权限检查执行更新 const updatedPost await prisma.post.update({ where: { id }, data: updates, }); return updatedPost; });对于更复杂的角色权限系统RBAC你可能需要引入roles字段到 User 模型并在中间件或装饰器中根据角色进行权限校验。skrun 的架构允许你轻松地在现有认证基础上添加这类扩展。4.3 前端状态管理与 API 集成优化在前端如何优雅地管理从 skrun 后端获取的数据如前所述skrun 很可能推荐或集成了TanStack Query。假设我们使用它来获取文章列表// frontend/src/hooks/usePosts.ts import { useQuery, useMutation, useQueryClient } from tanstack/react-query; import api from ../lib/api; // 配置好的 axios 或 tRPC 客户端实例 // 获取文章列表 export function usePosts() { return useQuery({ queryKey: [posts], // 查询的唯一标识 queryFn: () api.get(/api/v1/posts).then(res res.data), staleTime: 5 * 60 * 1000, // 数据保鲜期 5 分钟 }); } // 创建新文章 export function useCreatePost() { const queryClient useQueryClient(); return useMutation({ mutationFn: (newPost) api.post(/api/v1/posts, newPost), onSuccess: () { // 创建成功后使旧的‘posts’查询失效触发重新获取 queryClient.invalidateQueries({ queryKey: [posts] }); }, }); } // 在组件中使用 function PostList() { const { data: posts, isLoading, error } usePosts(); const createPostMutation useCreatePost(); if (isLoading) return divLoading.../div; if (error) return divError: {error.message}/div; return ( div button onClick{() createPostMutation.mutate({ title: New Post })} Create Post /button ul {posts?.map(post li key{post.id}{post.title}/li)} /ul /div ); }TanStack Query 帮你自动处理了 loading 状态、错误状态、数据缓存、后台刷新、依赖查询的失效与重试等复杂逻辑。skrun 如果预置了它会让你在开发复杂交互的前端时如虎添翼。5. 部署上线与生产环境考量一个本地运行良好的项目最终需要部署到公网。skrun 生成的项目通常已经为部署做好了准备。5.1 部署选项与配置1. 全栈托管平台最省心Vercel对前端和 Serverless 函数可部署你的 Fastify 后端支持极佳。如果项目是前后端分离的可以将frontend部署为静态站点backend部署为 Serverless Function。Vercel 能自动识别框架配置非常简单。Railway / Render这两家是新兴的“以应用为中心”的 PaaS对 Docker 和任意 Node.js 应用支持很好。你几乎只需要连接 GitHub 仓库它们就能自动构建和部署。skrun 项目根目录的Dockerfile就是为这类平台准备的。2. 传统 VPS 部署 如果你有自己的云服务器如 AWS EC2, DigitalOcean Droplet可以使用 Docker Compose 进行部署。# 在服务器上 git clone your-repo cd your-repo # 复制生产环境 .env 文件并配置 cp .env.production .env # 使用 Docker Compose 启动所有服务应用、数据库等 docker-compose -f docker-compose.prod.yml up -d这种方式需要你自行管理服务器、域名、SSL 证书可用 Let‘s Encrypt等。5.2 生产环境关键调整从开发到生产有几个关键点必须检查环境变量确保生产环境的.env文件正确配置。NODE_ENVproductionDATABASE_URL指向生产数据库如云厂商的 PostgreSQL 服务如 Supabase, AWS RDS。绝对不要使用本地 SQLite。JWT_SECRET、SESSION_SECRET使用强随机字符串且开发和生产环境必须不同。OAuth 回调地址将 OAuth 提供商Google, GitHub中配置的回调 URL 从http://localhost:3000/api/auth/callback改为你的生产域名。数据库连接池生产环境数据库连接压力大需要在后端应用如 Fastify 插件中配置 Prisma 连接池参数或使用像pgBouncer这样的连接池工具。定期备份建立数据库自动备份机制。安全加固CORS在 Fastify 后端严格限制 CORS 来源只允许你的前端生产域名。Helmet确保 skrun 的后端已经使用了类似fastify/helmet的插件来设置安全的 HTTP 头。速率限制对登录、注册等公共 API 添加速率限制防止暴力攻击。性能与监控日志生产环境应使用结构化的 JSON 日志如 Pino并接入日志收集系统如 Logtail, Datadog。健康检查为后端服务添加/health端点供负载均衡器或监控系统检查。APM考虑接入应用性能监控工具如 Sentry, New Relic。实操心得对于个人项目或初创公司 MVP我强烈推荐从Railway 或 Render开始。它们抽象了服务器、网络、证书的复杂性让你能像使用 Vercel 一样部署全栈应用并且有慷慨的免费额度。将 skrun 项目部署上去通常只需要几分钟。这让你能真正专注于产品开发而不是运维。6. 常见问题、排查技巧与进阶思考即使有 skrun 这样的利器保驾护航在实际开发中依然会遇到各种问题。下面是一些我总结的常见“坑点”和解决思路。6.1 开发环境问题速查表问题现象可能原因排查步骤与解决方案后端服务启动失败1. 端口被占用2. 数据库连接失败3. 缺少.env文件或配置错误1.lsof -i :端口号查看占用或修改backend/.env中的PORT。2. 检查DATABASE_URL确保数据库服务已启动docker-compose up db。对于 SQLite检查文件路径是否存在且可写。3. 确认根目录或backend目录下有.env文件且变量名与代码中读取的 (process.env.XXX) 一致。前端热更新不工作Vite 配置或依赖问题1. 检查frontend/vite.config.ts是否有特殊代理配置冲突。2. 尝试删除node_modules和pnpm-lock.yaml/package-lock.json重新pnpm install。3. 检查控制台错误可能是某个依赖包不兼容。Prisma 迁移或生成客户端报错1. Schema 语法错误2. 数据库连接问题3. 权限不足1. 运行prisma format格式化并检查schema.prisma语法。2. 确认DATABASE_URL正确数据库可连接。3. 对 PostgreSQL确认连接用户有创建数据库和表的权限。开发时可用高权限用户生产环境务必使用专用低权限用户。第三方登录OAuth失败1..env中客户端 ID/Secret 错误或未设置2. 回调 URL 不匹配1. 去对应平台Google Cloud Console, GitHub Settings仔细核对并复制正确的CLIENT_ID和CLIENT_SECRET。2. 确保在 OAuth 平台配置的回调 URL 与你的应用实际运行地址包括端口完全一致。http://localhost:3000和http://localhost:5173是不同的。6.2 性能优化点随着业务增长你可能需要关注以下方面数据库索引为 Prisma Schema 中经常用于where、orderBy的字段添加index。使用prisma studio或直接连接数据库查看慢查询日志。API 响应缓存对于不常变动的数据如文章列表、用户资料可以在 Fastify 路由层或反向代理如 Nginx, CDN添加缓存。前端资源优化检查 Vite 打包产物使用rollup-plugin-visualizer分析包体积按需引入大型库。6.3 何时该用何时不该用 skrunskrun 非常适合以下场景快速启动新项目特别是 hackathon、内部工具、个人作品集或需要快速验证的创业想法。学习现代全栈架构它是一个优秀的、可运行的学习范例。中小型标准 Web 应用需要用户系统、CRUD 操作、REST/GraphQL API 的应用。你可能需要谨慎选择或深度定制 skrun 的场景极度特殊的业务需求如果你的应用领域非常垂直如实时游戏、高频交易核心架构可能与 skrun 预设的 MVC/API 模式差异巨大。对特定技术栈有强偏好如果你的团队是 Python/Django 或 Go 的死忠那么强行使用 Node.js 系的 skrun 可能不合适。超大规模应用虽然 skrun 的选型Fastify, Prisma性能很好但超大规模应用可能需要更细粒度的、定制化的微服务拆分和基础设施这时 skrun 更适合作为其中某个服务的起点。最后也是最重要的心得skrun 是一个优秀的起点但不是枷锁。它的所有部分都是可替换、可覆盖的。如果你不喜欢它预设的样式库可以换成 Chakra UI 或 MUI。如果你觉得 tRPC 不适合可以换回普通的 REST 客户端。框架的目的是提升效率而不是限制你的创造力。理解它背后的设计思想和集成方式比单纯使用它更重要。当你能够熟练地基于 skrun 进行定制和扩展甚至能从中汲取灵感来搭建自己团队的内部脚手架时你才真正掌握了这个工具的精髓。