Wasp 框架的愿景设计:从声明式 DSL 到规格驱动的声明式架构
【免费下载链接】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 仓库中 v0.12 版本文档 vision.md 为主体,逐条拆解官方对 Wasp 的设计愿景——把 Web 应用开发变成“写规格说明书”、以声明式语言作为统一 React / Node.js / Prisma 的“胶水代码”、实体(Entity)作为一等公民、开箱即用的 CRUD、智能操作、逃逸机制与极简部署——并结合同仓库内的语言定义、示例项目与部署配置,印证每条愿景在当前实现中的落点。读完本篇,你能理解 Wasp 为什么选择“规格/语言优先”而非“库优先”的架构路线,以及这套理念如何在真实代码中兑现。
一、核心理念:编程应该像写规格文档
愿景文档开篇给出了 Wasp 的根本目标(见 vision.md):
With Wasp, we want to make developing web apps easy and enjoyable, for novices and experts in web development alike. Ideal we are striving for is that programming in Wasp feels like describing an app using a human language - like writing a specification document where you describe primarily your requirements and as little implementation details as possible.
翻译过来是:Wasp 希望让 Web 应用开发对新手和专家都变得简单且愉快;理想状态是,在 Wasp 中编程的感觉像“用人类语言描述一个应用”——更接近于写一份规格说明书,你主要描述需求,尽量少描述实现细节。创建一个新的、生产可用的 Web 应用应当是容易的,把它部署到生产环境应当是直接的(straightforward)。
这一理念在文档站 introduction 中有呼应:main.wasp是应用的中心文件,开发者在其中从高层描述整个应用;而底层的“秘方”是 Wasp 编译器——它读取 Wasp 配置和你的 JavaScript/TypeScript 代码,输出客户端应用、服务端应用与部署代码。因为编译器“理解”你的代码,所以它可以代劳认证 UI、全栈类型安全、邮件发送、异步 Job、数据获取等大量样板工作,并且随框架版本升级自动维护这些生成的代码。
二、为什么是“语言/规格”而不是“库”:胶水代码哲学
v0.12 版愿景文档中最关键的架构论断是(vision.md#L10-L13):
That is why we believe Wasp needs to be a programming language (DSL) and not a library - we want to capture all parts of the web app into one integrated system that is perfectly tailored just for that purpose. On the other hand, we believe that trying to capture every single detail in one language would not be reasonable.
即:Wasp 必须是一门编程语言(DSL)而非一个库——它要把 Web 应用的所有部分捕获进一个为这个目的量身定制的集成系统。但官方同时承认,试图用一种语言捕获每一个细节是不合理的:React 之于组件、CSS/HTML 之于样式标记、JS/TS 之于逻辑,这些方案在各自领域已经非常成熟,Wasp 不打算替换它们。Wasp 把自己定位为声明式的“胶水代码”(declarative "glue" code):把这些专用方案统一起来,在它们之上提供“Web 应用”这一更高层的抽象。
这种“不做全能语言,只做上层粘合”的取舍,正是后来被称为“横向语言”(horizontal language)的由来。v0.12 时代的实现载体是.wasp文件中的声明式 DSL,其形态在 Wasp Language 文档 中有完整定义:
- 语言是声明式、静态类型的 DSL,语法上更接近 JSON、CSS 或 SQL,而不是 JavaScript 或 Python——它是配置语言,不是通用编程语言;
- 代码的核心是声明(declaration),形如
<declaration_type> <declaration_name> <declaration_body>,例如:
app MyApp { title: "My app" } route RootRoute { path: "/", to: DashboardPage } page DashboardPage { component: import { DashboardPage } from "@src/Dashboard.jsx" }- 类型系统分为基本类型(string、bool、number、dict、list、tuple,以及
ExtImport外部导入、pslPrisma Schema Language 代码块等)与领域类型(app、entity、query、action、page、route、api、job、crud等声明类型,及DbSystem、HttpMethod、EmailProvider等枚举),后者正是建模 Web 应用概念的部分,也是“领域类型让 Wasp 变得特别”的原因。
值得注意的历史演进:当前仓库中的最新版文档 web/docs/vision.md 已将同一愿景更新为“Wasp 需要是一个spec-driven framework(规格驱动的框架)而非仅仅是库”,愿景清单的第一条也从“Declarative, static language”改为“Declarative, statically typed spec”(声明式、静态类型的规格)。从 v0.12 的.waspDSL 到当前仓库中的 TypeScript 规格(TS Spec),这条“语言/规格优先”的主线从未改变,改变的只是承载形式。
三、愿景清单逐条印证:十条设想在仓库中的落点
v0.12 愿景文档列出了十条具体设想(vision.md#L18-L30)。下面逐条对照仓库中的实现证据。
3.1 声明式、静态的“横向语言”,支持多文件与库
Declarative, static languagewith simple basic rules andthat understands a lot of web app concepts- "horizontal language". Supports multiple files/modules, libraries.
这一条直接对应 general/language.md 中对 Wasp 语言的定义:简单的基本规则、静态类型检查(如把app声明体的title字段写成little会直接触发 Wasp 编译器的类型错误)、多模块/多文件支持。当前仓库中这一愿景进一步落地为 TypeScript 规格:示例项目 examples/kitchen-sink/main.wasp.ts 展示了规格如何按功能拆分为多个模块文件——auth.wasp、crud.wasp、db.wasp、jobs.wasp、apis.wasp、chat.wasp等各自独立,再由 app 声明 汇总:
export default app({ name: "KitchenSink", wasp: { version: "0.26.0" }, title: "Wasp Kitchen Sink", webSocket, auth: authConfig, server: { setupFn: serverSetup, middlewareConfigFn: serverMiddlewareFn, envValidationSchema: serverEnvValidationSchema, }, client: { rootComponent: App, setupFn: clientSetup, envValidationSchema: clientEnvValidationSchema, }, db, emailSender: { provider: "SMTP", defaultFrom: { email: "kitchen-sink@wasp.sh" } }, spec: [route("HomeRoute", "/", page(HomePage), { prerender: true }), authSpec, operationsSpec, jobsSpec, ...], });“横向语言”在这里体现得非常直白:路由、认证、Job、API、数据库、WebSocket、邮件发送全部是同一种规格里的平级声明,而不是散落在多个框架的配置里。
3.2 与主流技术无缝集成:内联或外部文件
Integrates seamlessly with the most popular technologiesfor building specific, more complex parts of the web app (React, CSS, JS, ...). They can be used inline (mixed with Wasp code) or provided via external files.
“胶水代码”定位的具体化:Wasp 不替代 React/CSS/JS,而是集成它们。证据在规格语言本身的类型系统中——ExtImport类型允许在声明体内直接写import { DashboardPage } from "@src/Dashboard.jsx"(路径以@src开头,相对src目录解析),即“内联”方式;同时 project/customizing-app.md 展示了client、server、head等字段如何引用外部组件与脚本。示例项目里 React 页面、CSS 框架、JS/TS 逻辑代码全部原样保留在src/目录中,Wasp 只在main.wasp(或现在的main.wasp.ts)一层把它们组织起来。
3.3 逃逸机制(Hatches):在正确的地方定制,平时保持隐藏
Has hatches (escape mechanisms) that allow you to customize your web appin all the right places, but remain hidden until you need them.
这是 Wasp 设计中非常实用的一条。v0.12 文档中两处典型 hatch:
- 服务端(project/server-config.md):
server.setupFn声明一个在服务启动时执行的函数,可直接拿到 Express 的app实例挂自定义路由;server.middlewareConfigFn用于定制中间件:
// src/myServerSetupCode.ts import { ServerSetupFn } from 'wasp/server' import { Application } from 'express' export const mySetupFunction: ServerSetupFn = async ({ app }) => { app.get('/customRoute', (_req, res) => { res.send('I am a custom route') }) }- 客户端(project/client-config.md):
client.setupFn提供等价的客户端启动钩子。
这些字段不配置时完全不存在,配置后又能直通底层框架——正是“平时隐藏、需要时打开”的 hatch 形态。当前仓库的 kitchen-sink 示例中server.setupFn/client.setupFn仍是同一机制,说明这一设计从 v0.12 起是稳定的。
3.4 Entity(数据模型)是一等公民
Entity (data model) is a first-class citizen- defined via custom Wasp syntax and it integrates very closely with the rest of the features, serving as one of the central concepts around which everything is built.
v0.12 中实体用自定义 Wasp 语法(内嵌 PSL 代码块)定义,见>entity Task {=psl id Int @id @default(autoincrement()) description String isDone Boolean psl=}
底层由 Prisma 承载(psl即 Prisma Schema Language)。各示例项目中的 schema.prisma 与 migrations 目录印证了这条链路:Wasp 实体声明 → Prisma 数据模型 → SQL 迁移。
3.5 开箱即用的 CRUD:一条声明生成整套后端逻辑
Out of the boxsupport for CRUD UI based on the Entities, to get you quickly going, but also customizable to some level.
这条愿景在 v0.12 时代已经以Automatic CRUD功能落地(data-model/crud.md):一条crud声明就能让 Wasp 自动为实体生成创建、读取、更新、删除的服务端逻辑(Queries 和 Actions),并随实体定义的变化自动重新生成:
crud Tasks { entity: Task, operations: { getAll: { isPublic: true, // by default only logged in users can perform operations }, get: {}, create: { overrideFn: import { createTask } from "@src/tasks.js", }, update: {}, }, }其中getAll、get、update用默认实现,create指定了自定义实现(overrideFn正是 hatch 思想的体现:默认能力开箱即用,需要时逐操作覆盖),且每个操作可独立控制公开/私有权限。
3.6 “智能”操作(Queries 与 Actions):尽量消除客户端-服务端的心智负担
"Smart" operations (queries and actions)that in most cases automatically figure out when to update, and if not it is easy to define custom logic to compensate for that. User worries about client-server gap as little as possible.
v0.12 文档 contenteditable="false">【免费下载链接】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),仅供参考