Wasp 0.13 框架入门:一个编译器如何把 React、Node.js 与 Prisma 粘合成全栈应用

发布时间:2026/9/14 15:55:07
Wasp 0.13 框架入门:一个编译器如何把 React、Node.js 与 Prisma 粘合成全栈应用 Wasp 0.13 框架入门一个编译器如何把 React、Node.js 与 Prisma 粘合成全栈应用【免费下载链接】waspThe batteries-included full-stack framework for the AI era. Develop JS/TS web apps (React, Node.js, and Prisma) using declarative code that abstracts away complex full-stack features like auth, background jobs, RPC, email sending, end-to-end type safety, single-command deployment, and more.项目地址: https://gitcode.com/GitHub_Trending/wa/wasp本文基于 Wasp 官方 0.13 版介绍文档展开回答三个问题Wasp 作为全栈框架的定位是什么、它的核心Wasp 编译器如何工作、以及main.wasp声明式代码具体长什么样。读完之后你能完整复述 Wasp 从声明到生成的全链路app声明 →entityPrisma Schema Language→query/actionOperation→route/page→ 由编译器输出的客户端、服务端与部署代码并据此判断自己的项目是否适合用 Wasp。Wasp 是一个构建现代 Web 应用的工具WaspWebApplicationSpecification是一种有主见的opinionated全栈 Web 应用构建方式它同时接管 Web 应用的三大组成部分客户端Client前端React 组件服务端Server后端Node.js 中的查询与动作数据库Database通过 Prisma 定义的数据模型。一个关键的设计立场是Wasp 不试图一次做所有事情。它专注于把客户端、服务端、数据库、部署这些部分连接在一起时产生的复杂度——也就是胶水代码、类型同步、安全加固这一层。与现有技术栈协作而不是替换它Wasp 底层使用React、Node.js 和 Prisma并依赖它们来定义 Web 组件、服务端查询与动作。这意味着你现有的前端/后端技能可以直接迁移页面仍然是 React 组件服务端逻辑仍然是普通的 JavaScript/TypeScript 函数数据模型仍然是 Prisma 风格的结构。Wasp 只是站在它们之上做组织与连接。核心机制Wasp 编译器Wasp 的秘密配方secret sauce是位于核心的Wasp 编译器它接收 Wasp 声明文件Wasp config/spec和你的 JavaScript 代码输出三样东西——客户端应用、服务端应用、部署代码。一个能理解你的代码的编译器可以替你完成大量工作。在main.wasp中声明应用后你直接获得登录/注册Auth UI 组件全栈类型安全full-stack type safety邮件发送异步处理任务Jobs基于 React Query 的数据获取安全最佳实践以及更多。这些功能不需要你手写任何代码而且 Wasp 会替你维护这些生成代码——不需要担心跟进最新的安全实践因为 Wasp 升级你的应用代码随之升级。这个编译器在仓库中是有对应实现的Wasp 的核心工具链位于 waspc 目录下代码生成器的主逻辑在 waspc/src/Wasp/Generator/ 中从源码结构看它由若干子生成器组成包括WebAppGeneratorWeb 应用骨架、ServerGenerator服务端、Crud实体 CRUD、AuthProviders认证、DockerGenerator部署、SdkGeneratorSDK等模块——这印证了文档所说编译器输出客户端、服务端和部署代码的说法。编译器产物会落入项目.wasp/目录仓库 README 也说明生成代码可在此查看不存在供应商锁定。代码长什么样一个食谱分享应用的完整走查文档用一个经典例子说明 Wasp 代码形态构建一个允许用户创建和分享自己最喜欢的食谱的 Web 应用。下面完整继承该例子的每个步骤。第一步main.wasp——应用的中心声明文件main.wasp是应用的中心文件在其中从高层描述整个应用。给应用一个标题并立即开启基于用户名和密码的全栈认证app RecipeApp { title: My Recipes, wasp: { version: ^0.13.0 }, auth: { methods: { usernameAndPassword: {} }, onAuthFailedRedirectTo: /login, userEntity: User } }各字段的含义title是应用标题wasp: { version }锁定项目所使用的 Wasp 版本auth.methods声明启用用户名密码登录onAuthFailedRedirectTo: /login指定未认证时重定向的目标路由userEntity: User把认证系统绑定到下面的User数据实体。第二步用 Prisma Schema Language 定义数据模型接着定义食谱的数据模型——User实体且用户可以拥有多个Recipe... entity User {psl // Data models are defined using Prisma Schema Language. id Int id default(autoincrement()) recipes Recipe[] psl} entity Recipe {psl id Int id default(autoincrement()) title String description String? userId Int user User relation(fields: [userId], references: [id]) psl}注意{psl ... psl}标记0.13 版的main.wasp是 Wasp 自己的 DSL 文件其中直接内嵌了 Prisma Schema LanguagePSL片段来声明实体——这是该版本 DSL 的典型写法。实体之间的关系user外键指向User.id用标准 Prismarelation语法表达因此与schema.prisma中的模型完全同构。第三步定义 Operation——服务端可被客户端调用的函数要操作这些数据模型需要定义Operation。本例定义一个Query getRecipes和一个Action addRecipe它们的本质是运行在服务端、但借助 Wasp 可以被客户端轻松调用的 Node.js 函数。首先在main.wasp中声明这些 Operation让 Wasp 知道它们的存在并可以增强beef them up// Queries have automatic cache invalidation and are type-safe. query getRecipes { fn: import { getRecipes } from src/recipe/operations.ts, entities: [Recipe], } // Actions are type-safe and can be used to perform side-effects. action addRecipe { fn: import { addRecipe } from src/recipe/operations.ts, entities: [Recipe], }这里有两个要点fn通过import指向你自己的 JS/TS 实现文件src是指向项目源码根的路径别名entities: [Recipe]声明该 Operation 触碰哪些实体Wasp 据此实现自动缓存失效等机制。Query具备自动缓存失效且类型安全Action类型安全且可执行副作用。然后在 JavaScript此处用 TypeScript中实现它们// Wasp generates the types for you. import { type GetRecipes } from wasp/server/operations; import { type Recipe } from wasp/entities; export const getRecipes: GetRecipes{}, Recipe[] async (_args, context) { return context.entities.Recipe.findMany( // Prisma query { where: { user: { id: context.user.id } } } ); }; export const addRecipe ...可以看到Wasp 为你生成了类型GetRecipes{}, Recipe[]实现函数内部通过context.entities.Recipe直接使用 Prisma 客户端并通过context.user拿到当前认证用户——服务端上下文数据库句柄、当前用户、认证会话都由框架注入无需手工拼装。第四步定义路由与页面再在 React 中消费 Operation最后创建应用主页。先在main.wasp中定义... route HomeRoute { path: /, to: HomePage } page HomePage { component: import { HomePage } from src/pages/HomePage, authRequired: true // Will send user to /login if not authenticated. }route把 URL 路径映射到pageauthRequired: true表示未认证访问会跳转到/login。然后在 JS/TS 中把它实现为 React 组件调用之前定义的 Operationimport { useQuery, getRecipes } from wasp/client/operations; import { type User } from wasp/entities; export function HomePage({ user }: { user: User }) { // Due to full-stack type safety, recipes will be of type Recipe[] here. const { data: recipes, isLoading } useQuery(getRecipes); // Calling our query here! if (isLoading) { return divLoading.../div; } return ( div h1Recipes/h1 ul {recipes ? recipes.map((recipe) ( li key{recipe.id} div{recipe.title}/div div{recipe.description}/div /li )) : No recipes defined yet!} /ul /div ); }至此应用已经能列出所有食谱。客户端侧useQuery(getRecipes)直接消费在声明文件中注册的 Operation——客户端拿到的就是类型安全的远程调用从服务端的context.entitiesPrisma到客户端的useQueryReact Query之间类型全链路贯通。这就是文档强调的全栈类型安全的完整含义。两点补充说明示例为保持简洁省略了/login和/signup页面的定义实际使用时借助 Wasp 的 Auth UI 功能即可非常简单地完成完整的分步教程见 0.13 版文档的 Todo App 教程第一步安装步骤见 Quick Start。版本演进对照0.13 的main.waspDSL 与当前仓库的 TypeScript Spec需要特别注意适用前提本文基于的是version-0.13的文档彼时应用的中心文件是main.wasp自定义 DSL实体用{psl ... psl}内嵌 PSL 声明。而当前仓库0.26 代已将中心文件演进为main.wasp.ts——一个 TypeScript Spec 文件数据模型独立到schema.prisma。以仓库中的 Todo 示例 examples/tutorials/TodoAppTs/main.wasp.ts 为例同样的应用描述变成了import { action, app, page, query, route } from wasp.sh/spec; import { createTask, updateTask } from ./src/actions with { type: ref }; import { LoginPage } from ./src/LoginPage with { type: ref }; import { MainPage } from ./src/MainPage with { type: ref }; import { getTasks } from ./src/queries with { type: ref }; import { SignupPage } from ./src/SignupPage with { type: ref }; export default app({ name: TodoApp, wasp: { version: 0.26.0 }, title: TodoApp, auth: { userEntity: User, methods: { usernameAndPassword: {} }, onAuthFailedRedirectTo: /login, }, spec: [ route(RootRoute, /, page(MainPage, { authRequired: true })), route(SignupRoute, /signup, page(SignupPage)), route(LoginRoute, /login, page(LoginPage)), query(getTasks, { entities: [Task] }), action(createTask, { entities: [Task] }), action(updateTask, { entities: [Task] }), ], });可以看到 0.13 文档中的所有概念——auth声明、query/action及其entities元数据、route/page与authRequired——在新形态中都一一对应地保留了只是从 Wasp DSL 语法换成了 TypeScript 模块化的函数调用形式with { type: ref }标记指向真实 JS/TS 实现的引用。examples/ask-the-documents/main.wasp.ts 则展示了更大规模的用法Google 社交登录认证、服务端环境变量校验server.envValidationSchema等。若要从 0.13 迁移到新版可参考仓库中的 迁移指南。何时使用 WaspWasp 解决的是与传统 Web 应用框架相同的核心问题很大程度上它也看起来、游起来、嘎起来鸭子测试都像一个 Web 应用框架。文档给出的使用边界非常明确适合使用 Wasp 的场景构建全栈 Web 应用例如类似 Airbnb、Asana 这类应用用行业最佳实践快速启动一个 Web 应用与现代 Web 开发技术栈配合使用当时支持 React 和 Node.js。应避免使用 Wasp 的场景构建静态/展示型网站把它当作无代码no-code方案指望它是一门语言解决所有问题的工具。本质Wasp 是一门 DSL这是理解 Wasp 定位最重要的一个认知Wasp 不符合人们对 Web 应用框架的典型预期——它不是一组库而是一门能理解你的代码、能替你干很多活的简单编程语言。更准确地说Wasp 是一门特定类型的编程语言领域特定语言DSL, Domain Specific Language专用于构建现代 Web 应用这一个目的。日常常用的 DSL 例子包括数据库用的SQL和网页布局用的HTML。DSL 存在的主要优势在于它们只需要完成一件事例如数据库查询因此可以做得很好并为开发者提供最好的体验。Wasp 背后正是同样的思想——一门让开发者用 10 倍更少的代码、更少的栈相关知识来构建现代 Web 应用的语言。不需要懂 DSL 是什么概念也能使用 Wasp这只是理解其设计哲学的辅助视角。延伸阅读本文依据Wasp 0.13 版介绍文档原始出处含全部示例代码当前版本文档中的最新版介绍对应仓库现行main.wasp.ts形态编译器实现源码waspc/src/Wasp/Generator/代码生成器各子模块可运行的完整示例examples/tutorials/TodoAppTs/main.wasp.ts、examples/ask-the-documents/main.wasp.ts【免费下载链接】waspThe batteries-included full-stack framework for the AI era. Develop JS/TS web apps (React, Node.js, and Prisma) using declarative code that abstracts away complex full-stack features like auth, background jobs, RPC, email sending, end-to-end type safety, single-command deployment, and more.项目地址: https://gitcode.com/GitHub_Trending/wa/wasp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考