- 后端
- 前端
- Web框架
- 开发工具
【免费下载链接】redwood
RedwoodGraphQL
RedwoodJS 是一个将 React 前端与 GraphQL/Prisma 后端深度捆绑的全栈 Web 应用框架,本指南基于仓库内 What is Redwood? 展开,逐一拆解其"一个命令启动双应用"的 monorepo 架构、声明式 Router、Cell 数据获取约定、服务层与 SDL 的安全模型,以及生成器、Jest、Storybook 等开箱即用的工程化能力。读完本文,你将理解 RedwoodJS 各核心模块之间的调用关系与源码级实现原理,并能直接上手搭建、查询与部署一个全栈应用。
RedwoodJS 是什么
RedwoodJS 是一个"React 框架 + 大量预装包与配置"的组合体,目标是让开发者用最小的心智负担构建全栈 Web 应用。它内置的核心技术栈包括:
- GraphQL:前端与后端之间的数据通信协议
- Prisma:数据库访问、迁移与类型安全的 ORM
- Jest:单元与集成测试框架
- Storybook:组件隔离开发与 UI 目录
- Vite:前端打包器与开发服务器
- Babel:后端代码编译器
- TypeScript:全框架严格类型支持
所谓"全栈 Web 应用",指的是浏览器中可见的 UI(前端)与提供服务的服务器、数据库(后端)的组合。在 React Server Components 出现之前,React 本身并不知道服务器和数据库的存在,开发者只能通过fetch()或在构建步骤中把数据预烘到组件里。RedwoodJS 的核心设计原则之一,就是让"从后端取数据"这件事变得尽可能简单:它为此建立了强约定,让你在组件里加几行代码就能取回数据,并且自动处理加载中、出错、以及返回空数据("空白页")三种状态。
一个 Redwood 应用是如何运转的
一个 Redwood 应用实际上包含两个应用:前端(React 部分)与后端(服务器,负责与数据库及第三方系统通信)。从结构上看,它本质是一个 monorepo,包含两个顶层目录:
web:前端代码api:后端代码
你可以用一条命令同时启动它们:
yarn redwood dev这条命令会并行拉起 Vite(服务web目录)与基于 Fastify 的 API 服务器(服务api目录),开发者无需手工配置端口、代理或跨域,这正是 Redwood 将"配置交给自己、把复杂度留给框架"的体现。
前端:声明式 Router 与页面组织
浏览器打开应用后,React 负责初始化并监听 history 变化以切换内容。Redwood 提供了自定义的声明式 Router,让你直接以 JSX 声明 URL 与页面(页面本身就是一个 React 组件)的对应关系。一个典型的路由文件长这样:
import { Route, Router, Set, PrivateSet } from '@redwoodjs/router' import ApplicationLayout from 'src/layouts/ApplicationLayout' import { useAuth } from './auth' const Routes = () => { return ( <Router useAuth={useAuth}> <Set wrap={ApplicationLayout}> <Route path="/login" page={LoginPage} name="login" /> <Route path="/signup" page={SignupPage} name="signup" /> <PrivateSet unauthenticated="login"> <Route path="/dashboard" page={DashboardPage} name="dashboard" /> <Route path="/products/{sku}" page={ProductsPage} name="products" /> </PrivateSet> </Set> <Route path="/" page={HomePage} name="home" /> <Route notfound page={NotFoundPage} /> </Router> ) }这段代码即使第一次接触也能大致读懂:某些路由被<PrivateSet>标记为必须登录才能访问;另一些则被wrap进一个"布局"(同样只是 React 组件),用于在多个页面之间共享统一样式。
从源码看,Route、Set、PrivateSet都是"虚拟组件"——它们永远不会真正被渲染,而是由 router.tsx 中的analyzeRoutes()一次性提取出路径与页面映射,再在 Route.tsx 的类型定义中暴露path、page、name、prerender、renderMode、whileLoadingPage等属性。WrappedPage通过reduceRight把<Set wrap={[a,b,c]}>层层嵌套为<a><b><c>...</c></b></a>;若是<PrivateSet>,还会在最外层包上一个AuthenticatedRoute(见 router.tsx)。AuthenticatedRoute在未登录时会把用户重定向到unauthenticated指定的路由,并附上?redirectTo=参数以便登录后回跳(见 AuthenticatedRoute.tsx)。
预渲染(Prerender)
如果你的页面内容可以完全静态化(比如面向公众的营销页),只需在路由上加上prerender属性,该页面就会被完整渲染成 HTML——无论内部组件嵌套多深。这个 HTML 秒开,但依然携带 React 所需的 JS;React 加载完成后页面会被水合(rehydrate)并恢复交互。
预渲染同样支持从 URL 提取变量的路由,比如上面的/products/{sku}:Redwood 会遍历所有可用的 sku,为每一个生成一个静态页面。这正是 Redwood 版本的静态站点生成(SSG)。更妙的是,预渲染对 Cell 同样生效——构建时 Redwood 会启动 GraphQL 服务器,像真实用户一样发出请求,把结果渲染成纯 HTML 交给浏览器瞬间加载。更详细的机制可参考 prerender 文档。
认证(Authentication)
<PrivateSet>限制了只有登录用户能访问,那用户如何登录?Redwood 内置了大量第三方认证服务商的集成,包括 Auth0、Supabase、Clerk 等;你也可以自托管认证(自带登录、注册、重置密码页面,甚至支持 TouchID/FaceID 及第三方生物识别设备),或编写自定义认证方案。认证配置的完整说明见 authentication.md。
登录之后,如何判断某个用户能做什么、不能做什么?Redwood 提供了**基于角色的访问控制(RBAC)**辅助工具,可同时作用于前后端,详见 role-based-access-control 指南。
GraphQL:前后端的胶水
Redwood 用 GraphQL 作为前后端之间的胶水:任何来自服务器/数据库的数据都要经由 GraphQL 获取。前端使用Apollo Client,它提供useQuery()、useMutation()这类 hooks 来读写数据。但 Redwood 做得远比"给你一个 GraphQL 库"更深——它把数据获取封装进了组件本身。
Cell:自带数据获取的"超级组件"
Cell 依然只是一个 React 组件(也常被称为"单文件组件"),只是它遵循几条约定,从而具备自取数据、自管状态的能力:
- 文件名以
Cell结尾; - 文件导出若干具名组件,至少要有
QUERY和Success; - 可选导出
Loading、Failure、Empty——看名字就能猜到它们的用途。
每当 React 要渲染一个 Cell 时,会触发如下生命周期:
- 先显示
Loading组件; - 触发一次
useQuery(),使用导出的QUERY; - 数据成功返回后,渲染
Success组件,其中一个 props 就是useQuery()返回的数据; - 若出错则渲染
Failure;若查询返回null或空数组则渲染Empty;若未导出这两个组件,则仍渲染Success,由你在代码里自行处理错误与空态。
回到"评价墙"(testimonials)的例子,一个拉取并展示评价的 Cell 大概长这样:
export const QUERY = gql` query GetTestimonials { testimonials { id author quote } } ` export const Loading = () => <div>Loading...</div> export const Failure = ({ error }) => <div>An error occured! {error.message}</div> export const Success = ({ testimonials }) => { return ( <ul> {testimonials.map((test) => { <li key={test.id}>{test.quote} — {test.author}</li> })} </ul> ) }(本例未导出Empty,因此没有评价时页面该区域什么都不渲染,也不会提示用户缺少内容。)
源码层面,Cell 的执行逻辑集中在 createCell.tsx:它读取QUERY,支持beforeQuery(在查询前转换 props)、afterQuery(转换返回数据)、isEmpty(自定义空态判定)等可选 hook;随后依次判断renderLoading、Failure、Empty与Success的渲染时机。Cell 的完整约定与高级用法见 cells.md。
如果你将来为服务器开发其他客户端(比如移动 App),从一开始就用 GraphQL 会给你带来巨大的复用优势。另外别忘了:预渲染对 Cell 同样生效。
Apollo 缓存
Apollo Client 会智能缓存上面QUERY的结果:用户离开又回到首页时,Success会立即从缓存渲染,同时后台重新向服务器发起查询,若数据发生变化则合并进缓存并触发重渲染。这样既获得了缓存秒开的性能,又不会只看到过期数据——缓存始终与服务器最新状态保持同步。你还可以直接操作缓存增删条目,甚至把它当作状态管理工具使用。
可访问性
Redwood 内置了几个辅助屏幕阅读器的组件:<RouteAnnouncement>能让阅读器朗读一段内容(尽管它在浏览器中不可见);<RouteFocus>则引导阅读器跳过页面顶部的冗长导航直达正文。实现见 route-announcement.tsx 与 route-focus.tsx,更完整的说明见 a11y.md。
后端:服务层、Prisma 与安全模型
接下来进入api目录的后端代码。
Prisma:数据库访问层
Prisma 是 Redwood 用来与数据库通信的包,提供自动化迁移、类型安全与 IDE 自动补全。应用内会有一个schema.prisma文件,反映当前数据库结构:
datasource db { provider = "postgresql" url = env("DATABASE_URL") } generator client { provider = "prisma-client-js" binaryTargets = "native" } model Testimonial { id Int @id @default(autoincrement()) author String @unique quote String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt }Prisma 提供若干命令行工具,把这些文件变更翻译成 SQL DDL 命令执行到数据库,从而让库表结构与 schema 保持一致。变更数据库结构的完整工作流见>import { db } from 'src/lib/db' export const testimonials = () => { return db.testimonial.findMany() }
GraphQL 怎么知道解析器要去找这个函数?Redwood 引入了SDL 文件,它承载从 GraphQL 到 service 世界的映射:
export const schema = gql` type Testimonial { id: Int! author: String! quote: String! createdAt: DateTime! updatedAt: DateTime! } type Query { testimonials: [Testimonial!] @skipAuth } `type Query里列出的每个定义,都期望存在一个同名 service 函数:testimonials->testimonials()。服务层的更多模式见 services.md。
安全:默认安全(secure-by-default)与指令
Redwood 是默认安全的:任何未认证用户发出的 GraphQL 请求都不会被处理。你可以选择对某些查询/变更开放公共访问,但必须逐个手动开启。考虑一个更完整的 Testimonials SDL 文件:
export const schema = gql` type Testimonial { id: Int! author: String! quote: String! createdAt: DateTime! updatedAt: DateTime! } type CreateTestimonialInput { author: String! quote: String! } type Query { testimonials: [Testimonial!] @skipAuth } type Mutation { createTestimonal($input: CreateTestimonialInput!): Testimonial! @requireAuth deleteTestimonal($id: Int!): Testimonial! @requireAuth } `testimonials查询标记了@skipAuth(GraphQL 指令),表示该请求不限制为已认证用户;而关键的createTestimonial、deleteTestimonial变更标记了@requireAuth,只能由登录用户调用。这两个内置指令通过createValidatorDirective定义与注册,详见 makeDirectives.ts 与 directives.md。
后端 GraphQL 服务器由GraphQL Yoga驱动,因此你能获得 Yoga 在安全与性能上的全部能力:限速(rate limiting)与深度限制(depth limiting)、日志、指令,以及更多。@requireAuth与@skipAuth为整个 GraphQL 查询提供了"认证与否"的闸门,而进入闸门之后,你还可以基于"当前用户是谁"做更细粒度的控制。
认证上下文
如果用户已登录,他会在任何 service 的context对象中可用——处处可用、时时可用:
import { db } from 'src/lib/db' import { AuthenticationError } from '@redwoodjs/graphql-server' export const createTestimonial = ({ data }) => { if (context.currentUser.roles.includes('admin')) { return db.testimonial.create({ data }) } else { throw new AuthenticationError("You are not authorized to create testimonials") } }生成器(Generators)与开发者工具
命令行工具是许多框架中被忽视的部分,而 Redwood 在 CLI 上投入巨大,其中最有威力的是"生成器"(generators):用于创建文件、配置集成、执行脚本、启动开发服务器等等。
生成布局、页面和 Cell 能省下大量时间。Redwood 的文件本身样板代码不多,但生成器依然会把它们搭好,甚至为最小功能生成配套测试。生成器还提供对开发工具的快捷访问,比如:
- GraphiQL:直接对服务器执行 GraphQL 查询;
- Prisma Studio:提供数据库的完整 GUI。
Redwood 还提供针对 UI 库(如 Tailwind、Mantine)的setup命令,以及若干实验性新功能的开关,方便随时启用/禁用。此外还有一个交互式控制台,可以执行 Prisma 查询从数据库取数——当你想确认查询是否返回了预期数据时,不必往代码里塞一堆console.log()再刷新浏览器。CLI 命令全集见 cli-commands.md。
测试:Jest 与配套 helper
全栈应用开发如此顺畅,但如何验证它按预期工作?这就要靠测试套件。Jest以"简单"著称,Redwood 认为它与框架天然契合,因此大多数可生成的文件都会自动附带测试文件——甚至预先填好了一些测试。
Redwood 提供若干 Jest helper 与 matcher,可 mock GraphQL 请求、数据库数据、登录用户等:
- Scenarios:接受一个简单 JSON 对象,预先用这些数据填充数据库,让测试在已知状态下进行;
- Mock Service Worker:模拟 API 调用(包括 GraphQL)的响应;
mockCurrentUser():在web或api侧 stub 出登录用户,无需真正经过认证提供方。
你可以在应用的前端和后端都编写 Jest 测试。全部测试能力见 testing.md。
UI 开发:Storybook
Jest 负责测试代码逻辑,而Storybook用于编目与测试 UI——它自称"在隔离环境中构建 UI 组件的前端工作坊"。你可以脱离应用单独构建组件,甚至让 props 保持动态并实时观察效果。只需运行:
yarn redwood storybookRedwood 为 Storybook 增加了数据 mock 能力,让那些通常由 GraphQL 填充数据的组件可以在无需服务器运行的情况下展示。Storybook 严格属于前端代码的范畴,配置见 storybook.md。
构建与类型:vite、Babel 与 TypeScript
请注意,前面介绍的一切都从未出现"然后我们需要为这个包写配置……"——Redwood 已经把配置全部做好了,并在每个新版本中持续跟进。你几乎不会怀念花几小时甚至几天去添加并配置一个包的日子。当然,你可以从默认配置中"eject"出来加入自定义代码,但大多数应用永远不需要这么做:一切开箱即用。
- Vite是打包器,负责打包前端代码并按页面自动代码分割,同时作为
web目录的开发服务器; - api目录的后端代码由Babel编译,并由Fastify提供服务;
- 整个框架是(严格)类型化的,因此你可以在 IDE 里享受全量自动补全。TypeScript 的严格模式与工具类型见 strict-mode.md 与 utility-types.md。
部署
Redwood 的职责不止于把应用跑起来,还包括把它部署到全世界。它内置了针对主流托管平台的部署命令与配置(无论 serverless 还是传统服务器),支持:
- Coherence(GWC/AWS)
- Flightcontrol.dev(AWS)
- Edg.io
- Netlify
- Render
- Serverless.com
- Vercel
此外,你甚至可以通过 SSH 命令部署到自己的服务器——这就是 baremetal 部署方案。各平台部署指南见 deploy 目录。
演进方向、版本策略与社区
Redwood 仍在积极开发中,正围绕 React 生态的最前沿推进一系列功能:
- React Server Components以及全新的、非 GraphQL 的透明 API;
- SSR / Streaming渲染模式;
- Realtime 与 GraphQL Subscriptions;
- Redwood Studio:获取项目运行时洞察;
- Mailer:邮件发送能力。
Redwood 严格遵守语义化版本规范:不会有未经主版本号变更的突然破坏性变更。它因详尽的发布说明与全面的升级指南著称,当代码需要修改时,几乎都会附带 codemod 脚本替你完成迁移。围绕 Redwood 存在非常活跃的社区(Discourse 论坛与 Discord 聊天室),核心团队成员也会在其中回答问题。
小结
从本文可以看出,RedwoodJS 的竞争力不在于某个单一技术,而在于把 React、GraphQL、Prisma、Jest、Storybook、Vite、Babel 与 TypeScript 有机编排成一套"约定优先、配置收敛"的全栈开发体验:Router 与 Cell 消灭了前后端数据对接的样板代码,SDL 与服务层把 GraphQL 解析器映射变成惯例,@requireAuth/@skipAuth让安全默认生效,而生成器与预渲染进一步压缩了从想法到上线的时间。如果你想动手实践,可以接着阅读教程第一章,一步步构建自己的第一个 Redwood 应用。
- 后端
- 前端
- Web框架
- 开发工具
【免费下载链接】redwood
RedwoodGraphQL
相关推荐
RedwoodJS 全栈框架深度解析:React 前端、GraphQL API 与 Prisma 数据层的架构实践
RedwoodJS 全栈框架深度解析:React 前端、GraphQL API 与 Prisma 数据层的架构实践 RedwoodJS(仓库名 RedwoodG
后端前端Web框架开发工具TypeGraphQL与RedwoodJS集成:全栈框架的GraphQL支持
TypeGraphQL与RedwoodJS集成:全栈框架的GraphQL支持 在现代全栈开发中,GraphQL作为API查询语言正迅速取代传统REST架构。Ty
后端GraphQLAPI设计RedwoodJS 1.x 入门导读:从 side project 到 startup 的全栈 React + GraphQL 一体化框架
RedwoodJS 1.x 入门导读:从 side project 到 startup 的全栈 React + GraphQL 一体化框架 本篇技术指南以 Re
后端前端Web框架开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考