
Wasp TodoApp 教程示例应用全解析从本地运行到声明式全栈 Todo 应用【免费下载链接】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 仓库中的 TodoApp 教程示例应用展开它对应官方入门教程的最终形态用不到百行代码演示了 Wasp 的核心能力声明式应用配置、用户名密码认证、数据模型、查询Query与操作Action的端到端类型安全以及一键启动的本地开发流程。读完本文你将掌握如何在本仓库中运行该示例、理解main.wasp.ts声明式配置的每个关键字段并能从源码层面读懂 Wasp 如何把前端 React 页面、Prisma 数据模型与 Node.js 服务端逻辑串联成完整应用。示例应用概述examples/tutorials/TodoApp/README.md 明确指出这是一个配合 Wasp 入门教程使用的示例应用它通过一个简单的 Todo 应用展示如何用 Wasp快速且轻松地构建一个真正意义上的全栈 Web 应用。该示例代表了教程的最终完成状态——如果你希望跟随教程一步步从零搭建可以直接在仓库内找到完整的教程文档web/docs/tutorial/01-create.md 起共 7 个章节配套的 23 个补丁文件位于 web/docs/tutorial/patches。应用功能本身十分聚焦注册账号、登录、创建任务、勾选完成/未完成、退出登录。但麻雀虽小五脏俱全它同时覆盖了 Wasp 全栈框架的四大核心面关注点对应实现应用与路由声明main.wasp.ts数据模型schema.prisma前端页面src/MainPage.jsx、src/LoginPage.jsx、src/SignupPage.jsx服务端逻辑src/queries.js、src/actions.js端到端测试e2e-tests/tests/simple.spec.ts本地运行四步启动应用README 给出的本地运行流程非常简洁全程围绕wasp命令行工具展开。在开始前请确保本机已安装 Node.js示例使用type: module的 ESM 工程见 package.json。第一步安装 Wasp CLInpm i -g wasp.sh/wasp-clilatest全局安装最新的wasp.sh/wasp-cli这是后续所有wasp命令的入口。第二步进入项目目录并安装依赖、迁移数据库wasp install wasp db migrate-devwasp install会为当前项目安装依赖并校验main.wasp.ts中声明的 Wasp 版本约束。本示例声明wasp: { version: 0.26.0 }见 main.wasp.tsCLI 会根据该约束匹配对应版本的工具链。wasp db migrate-dev根据schema.prisma中的模型定义生成并执行数据库迁移。示例默认使用 SQLiteprovider sqlite数据库地址来自env(DATABASE_URL)见 schema.prisma仓库中migrations/目录下的 4 个迁移文件如20230907154352_add_extension、20240227091831_new_auth即历史迁移记录可以按需查看其 SQL 内容。第三步启动应用wasp startwasp start会同时启动开发服务器其中包含前端Vite React与后端Node.js Prisma两部分。值得留意的是 package.json 中的workspaces配置指向.wasp/out/*与.wasp/out/sdk/wasp——这正是 Wasp 的工作方式它读取main.wasp.ts声明后会把可运行的全栈代码生成到.wasp/out目录再由wasp/client/operations、wasp/client/auth、wasp/server等 SDK 入口被你的源码引用。启动后访问首页/即会自动跳转到登录流程因为首页路由声明了authRequired: true见下文。声明式配置读懂 main.wasp.tsWasp 与传统全栈框架最大的区别在于声明式框架的骨架在main.wasp.ts中描述业务实现则在src/中引用。本示例的 main.wasp.ts 全部代码仅 30 行却完成了应用定义、认证、路由、RPC 四件事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, head: [link relicon href/favicon.ico /], 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] }), ], });逐项拆解import ... with { type: ref }这是 Wasp 0.26 起使用的 TS Spec 语法with { type: ref }表示引用而非内联src/下的 JS/TS 实现。也就是说页面的 UI 代码、查询与操作的服务端逻辑都写在普通 React/Node 文件中配置层只负责把它们接线进框架。app({ name, title, head })应用名、浏览器标题、注入head的 HTML这里注入 favicon。auth块一行usernameAndPassword: {}即启用用户名密码认证userEntity: User指明认证实体onAuthFailedRedirectTo: /login定义未认证访问时的重定向目标。spec数组统一声明路由与 RPC。route(RootRoute, /, page(MainPage, { authRequired: true }))根路径映射到MainPage并开启必须登录保护query(getTasks, { entities: [Task] })把getTasks声明为查询Queryentities声明该查询可访问的实体Wasp 据此生成带权限上下文的 RPC 端点action(createTask, ...)/action(updateTask, ...)声明为操作Action即会修改数据的写操作。这种声明方式让路由守卫、认证方式、RPC 端点、数据库实体授权等原本分散在各层的样板代码全部收敛进一个文件生成的代码位于.wasp/out中由 Wasp 编译器自动维护。数据模型两个实体的关系设计schema.prisma 使用 Prisma Schema 定义数据模型Wasp 要求其中必须包含prisma-client-jsgenerator 且url指向DATABASE_URL环境变量model User { id Int id default(autoincrement()) tasks Task[] } model Task { id Int id default(autoincrement()) description String isDone Boolean default(false) user User? relation(fields: [userId], references: [id]) userId Int? }关键设计点Task通过userId外键关联User形成一对多关系——每个用户可以拥有多条任务isDone带default(false)新建任务默认未完成userId与user均为可空Int?/User?这是认证实体与业务实体解耦的常见做法实际归属关系在 Action 中通过context.user.id显式写入。前端页面认证表单与任务交互示例的 3 个页面都很简短但完整展示了 Wasp 客户端 SDK 的用法。登录/注册页直接使用 Wasp 内置认证 UI 组件LoginPage.jsx、SignupPage.jsximport { Link } from react-router; import { LoginForm } from wasp/client/auth; export const LoginPage () { return ( div style{{ maxWidth: 400px, margin: 0 auto }} LoginForm / br / span I dont have an account yet (Link to/signupgo to signup/Link). /span /div ); };LoginForm、SignupForm由wasp/client/auth提供框架根据auth.methods配置自动生成对应表单无需手写认证请求逻辑。主页面MainPage.jsx演示了 Wasp 的 React 数据流核心——useQuery钩子与 RPC 操作import { logout } from wasp/client/auth; import { createTask, getTasks, updateTask, useQuery, } from wasp/client/operations; export const MainPage ({ user }) { const { data: tasks, isLoading, error } useQuery(getTasks); // ... };useQuery(getTasks)把声明过的 Query 变成响应式数据源返回data / isLoading / error写操作完成后数据自动刷新MainPage的userprop 由框架注入受保护路由并可直接调用logout退出登录任务勾选通过updateTask({ id, isDone })提交新建任务通过createTask({ description })提交调用方式与本地异步函数完全一致——这正是 Wasp 端到端类型安全full-stack type safety在运行期的体现前端调用签名与服务端参数由同一份声明派生而来。服务端逻辑Query 与 Action 的鉴权细节Wasp 的 Query/Action 是服务端函数 客户端代理的封装。本示例的实现虽然简单却精准示范了基于登录用户的数据隔离这一经典需求。src/queries.js 中getTasks首先校验登录态再按当前用户过滤数据import { HttpError } from wasp/server; export const getTasks async (args, context) { if (!context.user) { throw new HttpError(401); } return context.entities.Task.findMany({ where: { user: { id: context.user.id } }, orderBy: { id: asc }, }); };src/actions.js 中createTask在创建时把任务挂到当前用户名下updateTask则用updateManywhere: { id, user: { id: context.user.id } }保证只能更新属于自己的任务import { HttpError } from wasp/server; export const createTask async (args, context) { if (!context.user) { throw new HttpError(401); } return context.entities.Task.create({ data: { description: args.description, user: { connect: { id: context.user.id } }, }, }); }; export const updateTask async (args, context) { if (!context.user) { throw new HttpError(401); } return context.entities.Task.updateMany({ where: { id: args.id, user: { id: context.user.id } }, data: { isDone: args.isDone }, }); };这里体现了 Wasp 的context结构它由框架自动注入包含user当前登录用户与entities按main.wasp.ts中声明的entities白名单暴露的 Prisma Client。context.entities.Task只能访问配置里声明过的实体多一层编译期约束。若开发环境缺少 Node 相关依赖导致wasp/server类型不可解析可参考仓库内对应用例中给出的排障方式见 CLAUDE.md。端到端测试认证与任务的自动化验证仓库为该示例配备了 Playwright 端到端测试e2e-tests/tests/simple.spec.ts它反过来印证了前文描述的每条用户故事注册流程随机生成用户名密码后调用performSignup断言跳转到/点击 Logout 后回到/login登录鉴权先故意使用错误密码断言页面出现Invalid credentials再用正确凭据登录断言进入/任务生命周期在input[namedescription]输入随机任务名并提交断言页面出现该任务勾选复选框后刷新页面断言复选框仍处于勾选状态——验证isDone状态确实持久化到了数据库。运行该测试套件可使用 package.json 中预置的脚本npm test它等价于npm run test:install-deps playwright test --config e2e-tests/先安装 Playwright 浏览器依赖再执行测试。测试配置位于 e2e-tests/playwright.config.ts公共步骤随机凭据生成、注册/登录操作封装在 e2e-tests/tests/helpers.ts。从示例到实战下一步可以做什么TodoApp 是理解 Wasp 心智模型的最佳起点你可以基于它做如下延伸仓库中均有对应参考实现扩展数据模型在schema.prisma中新增字段后运行wasp db migrate-dev并在对应 Query/Action 中使用增加 RPC在spec数组中新增query/action声明服务端逻辑写在src/前端即可直接调用参考更完整的示例仓库中 examples/kitchen-sink 覆盖了更丰富的功能组合社交登录、定时任务、乐观更新等examples/waspello 是一个带完整认证的看板类应用可作为进阶对照对照教程逐步构建仓库内的完整教程文档web/docs/tutorial/01-create.md 至 web/docs/tutorial/07-auth.md与patches目录下的 23 个补丁文件可帮你从空目录一路搭建到本示例的最终形态。总而言之这个不足百行业务代码的示例应用浓缩了 Wasp声明式全栈的核心主张路由、认证、RPC、数据访问全部声明在main.wasp.ts中业务代码保持纯前端/纯服务端的简单形态而框架负责在.wasp/out中生成并编排其余的一切。【免费下载链接】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),仅供参考