news 2026/9/13 17:53:23

Wasp 编译器(waspc)源码解析与贡献指南:从 Haskell 架构到全栈应用生成

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Wasp 编译器(waspc)源码解析与贡献指南:从 Haskell 架构到全栈应用生成

Wasp 编译器(waspc)源码解析与贡献指南:从 Haskell 架构到全栈应用生成

【免费下载链接】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

waspc是 Wasp 全栈框架的核心编译器与 CLI,它以 Haskell 实现编译管线,将声明式 Wasp 配置与src/目录中的 JS/TS 代码转换成一整套由 React 客户端、Node.js/Express 服务端与 Prisma 数据库组成的可运行 Web 应用。本文基于 waspc/README.md 的完整贡献者指南,结合仓库内run脚本、waspc.cabal与核心 Haskell 源码,系统讲解 waspc 的架构、开发环境搭建、构建测试流程、分支与发布策略,以及代码规范,帮助你快速上手这一编译器的源码开发。

waspc 是什么:编译器、CLI 与项目运行器的三位一体

在 Wasp 项目中,waspc指的是waspCLI/编译器的 Haskell 源码目录,但构建产物的可执行文件名并不是waspc。这一点很容易混淆,README 特别做了说明:

  • 正式发布时,可执行文件名为wasp
  • 开发阶段的可执行文件名为wasp-cli,用于与已安装的发布版区分。

从 waspc.cabal 可以看到,可执行文件定义为executable wasp-cli,入口为cli/exe/Main.hs,它依赖cli-libwaspc两个 Haskell 库。因此从产物角度看,wasp二进制同时承担了三重角色:编译器(把 Wasp 声明编译成 Web 应用)、CLInewstartdbbuilddeploy等命令入口,见 cli/exe/Main.hs 中的命令分发逻辑)、以及Wasp 项目运行器wasp start时编译并启动开发环境)。

# 查看当前 waspc 版本号 ./run get-waspc-version

仓库当前waspc.cabal中的版本为0.26.0(waspc.cabal),版本号管理遵循 SemVer 语义,详见后文"发布策略"一节。

第一份贡献清单:快速上手指南

README 为第一次向 waspc 提交代码的贡献者提供了一份四步清单:

  1. 阅读本文的 Codebase overview 快速了解编译器的整体结构;
  2. 成功编译项目,并跑通kitchen-sink示例应用(见下文 Basics);
  3. 加入社区 Discord,打个招呼;
  4. 挑选标有good first issue的 issue,主动提出工作计划并提问;随后创建面向main分支的 PR,参考 Typical workflow 与 Branching and merging strategy。

第 4 步是整个贡献闭环的关键:PR 的质量门禁是 CI 全部通过,因此建议在提交前完整执行一遍 Code analysis 中介绍的各项检查。

waspc 架构总览:Analyzer 与 Generator 两层管线

Wasp 编译器用 Haskell 实现,代码库分为**库(src/)**与CLI(cli/src/为库、cli/exe/为薄可执行包装)两部分。CLI 是实际的wasp可执行文件,绝大部分逻辑在库中。

从 src/Wasp/Analyzer.hs 的模块说明可以看到,编译管线分为两层:

  • Analyzer(前端):解析 Wasp 声明并做类型检查与求值。历史上它解析.waspDSL 文件,但该解析器已被移除,改为分析 TypeScript 配置文件(Wasp.Project.WaspFile.TypeScript);如今 Analyzer 保留的"解析 → 类型检查 → 求值"机制被复用于从 Prisma schema 推导实体声明:Analyzer.Prisma将 schema 转为 AST 实体语句,Analyzer.TypeChecker为 AST 补充类型信息,Analyzer.Evaluator把类型检查后的 AST 转换为 Wasp AST。
  • Generator(后端):接收 Analyzer 产出的中间表示AppSpec(定义于 src/Wasp/AppSpec.hs),基于它决定如何生成 Web 应用。

AppSpec是贯穿前后两层的中央 IR。从 src/Wasp/Generator.hs 可以观察到 Generator 的组装方式——genApp依次拼接多个子生成器:

genApp :: AppSpec -> Generator [FileDraft] genApp spec = do warnOverriddenDeps spec genServer spec <++> genSdk spec <++> genDb spec <++> genDockerFiles spec <++> genTypeAugmentation spec <++> genWaspLibs

README 中描述的 WebAppGenerator / ServerGenerator / DbGenerator 三个主生成器,在实现中体现为Wasp.Generator.WebAppGeneratorWasp.Generator.ServerGeneratorWasp.Generator.DbGenerator三个模块(见 waspc.cabal 的 exposed-modules 列表)。

一个关键设计理念是:Generator 本身不写文件。它的输出是FileDraft列表,每个 FileDraft 描述"如何在磁盘上创建某个文件"(如CopyFileDraftCopyLibDraftTemplateFileDraftTextFileDraft等类型,见 src/Wasp/Generator/FileDraft 目录)。最终由synchronizeFileDraftsWithDisk(在 src/Wasp/Generator.hs 的writeWebAppCode中调用)将草稿写入磁盘,完成应用生成。

FileDrafts 大量使用 Mustache 模板(存放于data/Generator/templates/),而生成的应用还依赖 Wasp 自带的内部 npm 包(WaspLibs),这些包随 Wasp 一起打包并安装进生成的应用中。

上图展示了完整的编译数据流:输入(Wasp 配置与src/资源)→ Analyzer(Parser → TypeChecker → Evaluator)产出AppSpec→ Generator 结合 Templates 驱动 Client/Server/DB 三个子生成器产出 FileDraft(FD)→ 写入磁盘生成 Web 应用。

生成出的 Web 应用技术栈为:客户端使用 React + TanStack Query(@tanstack/react-query),服务端使用 Node.js + Express,数据库层通过 Prisma 抽象。wasp start会先编译应用、在.wasp/out/目录生成 JS 代码,然后分别对 client 与 server 执行npm start并启动数据库;此后任何对 Wasp 源码的修改都会触发重新编译,client/server 的npm start会自动拾取变化。

从零搭建 waspc 开发环境

仓库准备与run脚本

克隆仓库后进入waspc/目录并确保处于main分支。README 特别强调:./run脚本(waspc/run)封装了 waspc 开发中最常用的命令,地位等同于 npm 项目中package.jsonscripts,既是快捷入口也是开发方式的文档。不带参数运行./run会打印全部可用命令的帮助信息。

可以为其创建 bash 别名方便调用:

alias wrun="/path/to/your/wasp-lang/wasp/waspc/run"

[!IMPORTANT]./run脚本及配套开发工具是 Bash 脚本,在 Windows 的 PowerShell 或 Command Prompt 中无法直接使用。

从 waspc/run 源码可以看到脚本的结构:COMMAND=${1:-watch}默认执行watch类命令,每个子命令(buildtestwasp-clistanhlint等)通过case分支映射到对应的底层命令。例如build实际执行:

# waspc/run 中的 BUILD_ALL_CMD node tools/packages/build.ts && node tools/libs/build.ts && cabal build all

wasp-cli命令则通过tools/wasp-cli-dev脚本(waspc/tools/wasp-cli-dev)以cabal -v0 --project-dir=... run wasp-cli -- "$@"的方式运行本地构建的 CLI,这样测试与开发调用总能反映waspc源码的最新状态,无需事先cabal install

构建、测试与运行 CLI

按顺序执行以下三条命令,即可完成第一轮"构建 → 验证 → 运行":

# 1. 构建整个 waspc 项目(Haskell + TS 包 + WaspLibs) ./run build # 2. 确保所有测试通过 ./run test # 3. 运行本地构建的 wasp-cli(无参数会打印帮助/用法) ./run wasp-cli

首次执行./run build可能需要约 10 分钟,因为要下载全部依赖(之后会被缓存)。开发期可执行文件名为wasp-cli,与正式安装后的wasp相区分——这正是方便开发者区分"开发版 CLI"与"发布版 CLI"的设计。

跑通 kitchen-sink 示例应用

examples/kitchen-sink/(examples/kitchen-sink)是 Wasp 团队始终维护的示例应用,用于手工验证对编译器的改动,也是新增功能的首选验证场。跑通它的步骤:

# 1. 进入示例目录 cd examples/kitchen-sink # 2. 启动开发数据库(保持运行,不要关闭该终端) ./run wasp-cli db start # 3. 新开一个终端,更新数据库 schema ./run wasp-cli db migrate-dev # 4. 准备服务端 mock 环境变量 cp .env.server.example .env.server # 5. 以开发模式启动示例应用 ./run wasp-cli start

首次执行第 5 步可能需要一分钟左右下载并安装 npm 依赖;完成后浏览器会自动打开新标签页并展示 Kitchen Sink 应用。

[!NOTE]kitchen-sink中的部分功能不会工作,因为.env.server里只是 mock 值。关于如何配置开发环境变量,请查看kitchen-sink自己的 README(examples/kitchen-sink/README.md)。

典型开发工作流:从分支到合入

README 给出了一套完整的迭代流程,结合 waspc/run 可以还原每一步的实际命令:

  1. main创建功能分支。
  2. 若 IDE 没有可靠的 HLS(Haskell Language Server,强烈建议配置),在waspc根目录运行./run ghcid:它会监视 Haskell 项目并持续报告编译错误,保持运行即可。ghcid需先全局安装:cabal install ghcid
  3. 修改代码(最常见于src/cli/src/data/目录),并视情况更新测试。对照 HLS/ghcid修复错误,循环迭代。
  4. ./run build:hs单独构建 Haskell/cabal 项目;./run wasp-cli则会构建并运行。若改动涉及data/packages/,还需执行./run build:packages(详见下文 TypeScript 包章节);嫌慢的话可以一步到位执行./run build同时构建 Haskell、TS 包等所有部件。
  5. 手工验证改动时使用kitchen-sink(保持更新);新增功能应同时加入该应用及其测试。
  6. 执行./run test确认全部测试通过。若 waspc e2e 快照测试出现预期变更,用./run test:waspc:e2e:accept-all接受新基线。
  7. 若做了 bug 修复、新功能或破坏性变更,在Changelog.md(waspc/ChangeLog.md)中补充简要说明;必要时同步提升waspc.cabalChangeLog.md中的版本号(版本确定方法见 Determining next version)。
  8. 创建 PR,紧盯 CI——一切必须通过。
  9. 若 PR 改变了用户使用 Wasp 的方式,同步更新同仓库web/docs下的文档。
  10. 与 reviewer 协作迭代直至 PR 获批。
  11. Reviewer 将分支合入main

团队内部成员的注意事项

不要在你的 PR 获批前更新 waspc e2e 测试。过早接受 e2e 测试会拖慢 UI、给 reviewer 制造噪音,并降低你在所有评审迭代后仔细核对最终 diff 的可能性。接受 waspc e2e 测试 diff 前务必仔细审查

深入 waspc 的关键目录

README 列出waspc/内的核心目录,结合 waspc.cabal 可以对应到实际的 Haskell 模块:

  • src/→ 主源码(库),对应 cabal 的library段;
  • cli/src/→ CLI 库代码,对应library cli-lib段,实现Wasp.Cli.Command.*系列命令模块(如Wasp.Cli.Command.Db.MigrateWasp.Cli.Command.DeployWasp.Cli.Command.News等,见 waspc.cabal);
  • cli/exe/→ 可执行文件薄包装(Main.hs),对应executable wasp-cli段;
  • tests/e2e-tests/cli/tests/starters-e2e-tests→ 各类测试;
  • data/Generator/templates/→ 生成 client/server 的 Mustache 模板;
  • data/Generator/libs/→ 随 Wasp 打包并复制进生成应用的内部 npm 包(WaspLibs);
  • data/packages/→ Wasp 编译器自身使用的 TypeScript 包;
  • data/Cli/starters/→ 新项目的 starter 模板。

TypeScript 包:Haskell 与 TS 的协作

waspc虽以 Haskell 实现,但部分功能(如解析 TS 代码、部署脚本)依赖 TypeScript。Haskell 代码将这些 TS 包作为独立进程运行,通过输入/输出流通信。这些包位于 waspc/data/packages/README.md 所述的data/packages/中,是标准 npm 项目;deployprismaspecstudio等包可在 waspc/waspc.cabal 的data-files中找到对应条目。

要让 Haskell 代码正确使用这些 TS 包(并在发布 tarball 中正确打包),需要它们在waspc_datadir目录中被正确安装/构建。开发中每当这些包有改动就运行:

./run build:packages

CI 构建 release 时也会执行同样的操作。data/packages/README.md还说明了新增包的规范:包目录需在package.json中提供build脚本和调用编译产物的start脚本,并在waspc.cabaldata-files中登记packages/<name>/package.jsonpackage-lock.jsondist/**/*.js等文件。

WaspLibs:生成应用的构建块

WaspLibs 是 Wasp 自有的 npm 包,位于 waspc/data/Generator/libs/,其中包含会进入生成应用的核心逻辑。README(waspc/data/Generator/libs/README.md)明确了两条向生成应用注入代码的途径:

  • waspc/data/Generator/templates/写 Mustache 模板;
  • 在 libs 目录中开发真正的 JS 项目。

模板不是真正的 JS 工程(含 Mustache 语法),无法写测试、无法类型检查;而 libs 是真正的 JS 工程,可以写测试并被类型检查。理想做法是大部分逻辑放在 libs 中,模板只负责产出配置对象并编排这些 lib

WaspLibs 的版本跟随 Wasp 编译器版本(如0.19.2),被视为 Wasp CLI 的实现细节。libs 的导出遵循按运行时区分的命名约定:

导出路径Node.js浏览器说明
.两种运行时通用
./node仅 Node.js 运行时
./browser仅浏览器运行时

例如authlib 的package.json中可通过exports字段暴露@wasp.sh/lib-auth(通用)、@wasp.sh/lib-auth/node(Node 专用)与@wasp.sh/lib-auth/browser(浏览器专用)三个导入路径。开发 lib 时运行./run build:libs将编译产物复制进data/;由于 npm 按版本缓存已安装包而 lib 版本不变,必要时在 Wasp 应用根目录执行./run bust-libs-cache清理所有@wasp.sh/lib-*的锁文件条目、重新编译并重装依赖。

测试体系:Tasty、Hspec、QuickCheck 与快照测试

waspc 的 Haskell 测试基于Tasty测试框架,它允许把多种类型的测试组合进同一个测试套件。测试以"测试树"形式组织,可递归分组、混合 hspec / QuickCheck 等不同类型。

为避免手工组织测试文件与导入,项目使用tasty-discover自动发现测试:它自动识别包含测试的文件并组装成测试树。测试函数需要特殊前缀来标明类型:spec*表示 Hspec 测试、prop*表示 QuickCheck 属性测试等;也可以手动组织 Tasty 测试树并用test_前缀让 tasty-discover 拾取。目前自动发现被限制为只匹配*Test.hs结尾的文件。

三个测试框架各司其职:Hspec用于单元测试,QuickCheck用于属性测试,doctest用于测试文档中的代码示例。所有测试放入tests/目录(Haskell 构建工具不擅长把测试与源码混放)。在 waspc.cabal 中可以看到三个测试套件:waspc-tests(单元测试,入口tests/TastyDiscoverDriver.hs)、wasp-cli-tests(CLI 测试)与waspc-e2e-tests(e2e 快照测试,入口e2e-tests/Main.hs,依赖tasty-golden)。

运行测试的完整命令家族如下:

./run test # 运行所有测试 ./run test:waspc # 仅 waspc 测试(单元 + e2e) ./run test:waspc:unit # 仅 waspc 单元测试 ./run test:waspc:unit "Some test description to match" # 按描述模式运行单个单元测试 ./run test:waspc:e2e # 仅 waspc e2e 测试 ./run test:cli # 仅 Wasp CLI 测试 ./run test:kitchen-sink # kitchen-sink e2e 测试 ./run test:examples # 所有 examples e2e 测试 ./run test:starters # starter 模板 e2e 测试

从 waspc/run 可以看到底层实现:test:waspc:unit执行cabal test waspc-teststest:waspc:e2e执行cabal test waspc-e2e-teststest:cli执行cabal test wasp-cli-teststest:examples则循环遍历examples/tutorials/TodoAppexamples/tutorials/TodoAppTsexamples/waspelloexamples/waspleauexamples/websockets-realtime-votingexamples/ask-the-documentsexamples/kitchen-sink七个示例目录,逐一执行wasp-cli install && npm run test

waspc e2e 快照测试:黄金输出的评审机制

waspc e2e 测试中有一类快照测试:对若干准备好的项目运行wasp-cli,验证它们能成功运行,并将生成的应用与期望的生成结果(golden 输出)做对比。

当你修改了影响生成应用的代码时,快照测试会失败并展示新旧输出的 diff。这给了你观察差异、确认其符合预期的机会。审查 diff 是 PR 作者(外部贡献则由 reviewer)的责任——不要盲目接受变更,务必确认与预期修改一致。确认满意后,用便捷命令接受新基线:

./run test:waspc:e2e:accept-all

从 waspc/run 看,该命令的实现是"删除当前 golden 输出 → 重跑快照测试生成新 golden"。

代码质量检查:格式化、lint 与静态分析

提交 PR 前,务必让以下检查全部通过——它们同样是 CI 的门禁:

./run code-check

该命令会依次执行代码格式化检查、lint 与静态分析,并输出汇总报告(waspc/run 的code-check分支分别记录 prettier / ormolu / cabal-gild / hlint / stan 五项结果)。目前 CI 只检查代码格式化,lint 与静态分析暂未纳入 CI(waspc/run 中的 TODO 注释说明未来会补上)。

格式化:Ormolu + cabal-gild + Prettier

Haskell 代码使用Ormolu格式化,通常在编辑器里配置保存时自动运行,也可手动执行:

./run check:ormolu # 检查是否存在需要格式化的文件 ./run format:ormolu # 就地格式化所有需要格式化的文件

此外,.cabal文件由 cabal-gild 格式化,仓库整体代码由 Prettier 格式化:

./run check:cabal / ./run format:cabal ./run check:prettier / ./run format:prettier ./run check # 全部 formatter 的 check 模式 ./run format # 全部 formatter 就地格式化

[!NOTE] 首次运行 Ormolu 相关命令时,安装依赖可能耗时约 10 分钟,后续运行会快得多。

Lint:hlint

使用hlint对 Haskell 代码做 lint:

./run hlint

静态分析:stan

使用stan对代码库做静态分析(waspc/run 显示stan会先完整构建项目再运行分析):

./run stan

该命令会构建代码库、以正确的 GHC 版本安装并运行 stan,结果输出到 CLI 并生成stan.html报告。首次运行同样需要约 10 分钟安装依赖。

分支与合并策略:main 与 release 的双轨模型

本仓库同时包含构成 Wasp 发布的源码(waspc/)以及包含文档与博客的网站(web/)。为兼顾新功能开发与线上文档/热修复,仓库采用最小化分支策略:

  • main:承载所有活跃开发的新功能与配套文档更新,可包含未发布的内容,但合入main的任何改动都应处于"可发布"状态。这是功能分支的默认目标分支。
  • release:包含当前/最近 Wasp 发布的源码,以及已发布、网站可见的文档与博客。

完整发布(基于main制作新版本)的流程是:先把release合并进main(可能有冲突但易解决),再从更新后的main制作 waspc 发布;随后把main合并回release(上一步已解决冲突,故无冲突)。

如何选择 PR 目标分支?

  • 需要立刻或很快发布的改动(网站内容、博客、文档热修复、需要以新 patch 版本快速发布的编译器热修复等)→ 目标为release
  • 不紧急、可等到下一个"常规" Wasp 发布的内容(新功能、重构、配套文档)→ 目标为main

一句话总结:release代表当下,面向已发布内容的改动;main代表近期未来,面向待发布内容的改动。

[!IMPORTANT] 若向release合并 PR 或推送任何改动,系统会自动创建一个把release变更同步到main的 PR,并分配给你负责合入。

CI 与发布流程

项目使用 GitHub Actions 作为 CI,在main分支的任何提交、PR 以及以v开头的 tag 上运行。CI 在 Linux、macOS 与 Windows 上构建并测试 Wasp 代码。

  • 提交以v开头的 tag 时,会创建包含二进制包的 GitHub draft release,并将 Wasp npm 包上传到 npm 的暂存队列(须经维护者批准才会发布)。

  • 另有部署示例应用到 Fly.io 的 workflow(release-examples-deploy.yaml),可在 GitHub UI 手动触发,通常应在发布新版本后从release分支运行,确保已部署示例使用最新稳定版 Wasp。也可用 GitHub CLI 触发:

    # 使用最新 Wasp 版本部署 gh workflow run release-examples-deploy --ref release # 使用指定版本部署 gh workflow run release-examples-deploy --ref release -f version=0.13.2
  • 提交信息中包含[skip ci]可跳过 GitHub Actions。

  • 仓库还提供new-release脚本辅助发版:传入新版本号(./new-release 0.3.0),它会检查一切就绪、创建对应 tag 并推送,从而触发 CI 在 GitHub 上创建新 release。

典型发布流程

以下步骤中带 👉 的步骤是每次waspc发布都必须执行的;其余步骤视改动情况决定(例如没有破坏性变更时可跳过部分步骤):

  • 确保 OpenSaaS 已更新到最新 Waspmain(手动运行其 e2e workflow)。
  • 👉 确保已将release分支的变更合并进main
  • 👉 拉取远端全部变更(git fetch),确保本地main是最新。
  • 👉 从要发布的最后一个提交(通常是最新main)创建名为rc-<version>的 RC 分支(如rc-0.24.1),后续步骤都在该分支进行。
  • 👉waspc.cabal中的版本号应已正确,但需复核并按需更新;若修改了waspc.cabal,创建 PR、等待审批与 CI 通过,再 squash 合并进 RC 分支。
  • 👉 创建 RC 发布并做测试与修复(见下文 Test releases),一切就绪后继续。
  • 👉 检查自上次发布以来的提交,斟酌完善ChangeLog.md与迁移指南。
  • 若是主版本更新,在 RC 分支上运行npm run docusaurus docs:version {version}为当前文档拍版本快照(在web/目录),提交到 RC 分支并推送。
  • 👉 切换到release分支,通过git merge --ff rc-<version>快进到 RC 分支。
  • 👉 准备正式发布时确保处于release分支,运行./new-release 0.x.y(脚本会做若干检查、打 tag 并推送)。
  • 👉 等待新 tag 的 CI 完成且成功(tag 推送自动触发;完成后创建 GitHub draft release 并把 npm 包放到暂存队列)。
  • 👉 找到 draft release,编辑发布说明(通常直接粘贴对应版本的 ChangeLog 条目),就绪后发布。
  • 👉 批准暂存的 npm 包:npm stage list查看 stage ID,npm stage approve <stage-id>逐一批准(需要 2FA)。
  • 👉 推送本地release分支到远端。
  • 👉 你会在自动生成的"把release合并回main"的 PR 中被 @(也可在 PR 列表按head:release base:main过滤找到),务必合并它——用 merge commit,不要 squash 或 rebase,确保main领先于release,避免未来发布产生合并冲突。
  • 通过release-examples-deployworkflow 把示例应用部署到 Fly.io。
  • 若有文档改动,从release分支发布新版本文档。
  • 在 Discord 宣布新版本。

版本号如何确定

waspc遵循标准 SemVer 的major.minor.patch方案。由于尚未到 1.0,遵循约定将major保持为 0,破坏性变更时提升minor

测试发布(RC)

制作测试发布(尤其是 Release Candidate)可以在不打扰普通用户的情况下先行验证。步骤:

  1. 从要发布的最后一个提交(通常是最新main)创建rc-<version>分支。

  2. 本地执行new-release脚本,并在版本号后追加-rc.N以标明预发布性质(如./new-release 0.24.1-rc.1),脚本会给出一些可接受的警告。

  3. draft release 创建后:用 UI 将其标记为 pre-release 并发布——这是区分测试发布与正式发布的关键一步(会自动取消"latest release"的勾选);同时把rc-<version>分支推送到远端。

  4. 批准暂存的 npm 包(npm stage list+npm stage approve <stage-id>,需 2FA)。

  5. 显式指定版本安装包进行验证:

    npm i -g @wasp.sh/wasp-cli@0.24.1-rc.1
  6. 创建 checklist 并走查发布前事项;发现问题就在rc分支上修复并照同样流程创建下一个 RC(如0.24.1-rc.2)。

文档、Haskell 实践与依赖策略

  • 外部文档:面向 Wasp 用户的文档托管于官网,其源码就在本仓库的 web/docs 目录中,与网站、博客同处web/下。
  • Haskell 最佳实践:项目维护独立的 Haskell Handbook 记录相关最佳实践。
  • Cabal 依赖冻结:项目刻意不使用 cabal freeze 文件来锁定依赖,而是借助 cabal 的index-state特性从 Hackage 获得包版本固定,以更好地支持更广泛的开发者操作系统(waspc/cabal.project 中可查看实际配置)。

代码风格指南

注释规范

  • 注释以大写字母开头时,必须以标点结束;不以大写开头则不应以标点结尾。

  • TODO / NOTE 一律全大写:

    -- TODO: Wash the car. -- NOTE: This piece of code is slow.
  • 可在 TODO / NOTE 后附加作者名,便于读者在需要时咨询原作者:

    -- TODO(martin): Doesn't work on my machine in some unusual use cases.

JavaScript 函数风格

  • 顶层具名函数优先使用函数声明语句,而非箭头函数或函数表达式:

    // good function foo(param) { // ... } // bad const foo = (param) => { // ... }; // bad const foo = function (param) { // ... };
  • 内联函数表达式优先使用箭头语法:

    // good const squares = arr.map((x) => x * x); // bad const squares = arr.map(function (x) { return x * x; });

设计文档(RFC):复杂功能的标准流程

如果实现的功能因设计或技术实现而复杂,README 推荐先写一份设计文档(RFC)。做法是提交一个 PR,在wasp/docs/design-docs下新增 Markdown 文档,阐述功能实现的思路与决策。其他人会在文档上评论,经过必要迭代并获得批准后,再在单独的 PR 中开始实现。

结语

waspc 以"Analyzer 产出 AppSpec、Generator 产出 FileDraft"的两层管线,将声明式配置精确转换为全栈应用,其工程实践(Bash 驱动的run开发工具链、Tasty 多框架测试体系、快照 golden 评审机制、双分支发布模型)本身就是一份高质量的编译器项目范本。无论你是想修复 bug、添加新功能,还是仅仅想理解一个真实 Haskell 编译器如何工作,都可以从./run开始,沿着本文的路径一步步深入。

【免费下载链接】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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 17:53:14

嵌入式开发六大实战避坑指南:从ISR误用到软硬版本绑定

1. 这不是一篇“悔过书”&#xff0c;而是一份嵌入式老兵的实战避坑清单干了这么多年嵌入式&#xff0c;我最后悔的几件事——这句话刚在技术群刷出来&#xff0c;底下秒回99条“1”“泪目”“正在重蹈覆辙”。它不像“如何学好C语言”那样带着教学意图&#xff0c;也不像“STM…

作者头像 李华
网站建设 2026/9/13 17:53:11

GE VCMIH2CB板卡替换的七项硬性技术约束

1. 这块板卡不是“能用就行”&#xff0c;而是“差0.1毫秒就跳机”的关键节点GE IS215VCMIH2CB——这个编号在Mark VIe燃机控制系统里&#xff0c;不是普通备件&#xff0c;它是VCMI&#xff08;Versatile Communication Module Interface&#xff09;系列中专为高实时性通信设…

作者头像 李华
网站建设 2026/9/13 17:52:45

Java实现论文查重系统:中文分词、N-Gram与相似度算法实战指南

简介&#xff1a;一份基于Java的论文查重系统完整源码包&#xff0c;面向计算机相关专业学生、Java开发者与文本相似度检测初学者。系统核心采用SimHash算法计算原文与待检测论文之间的相似度&#xff0c;输出重复率结果&#xff0c;支持文件输入输出和命令行参数指定路径&…

作者头像 李华
网站建设 2026/9/13 17:51:53

AI助力跨境电商商品描述本地化与转化提升

1. 项目背景与核心价值跨境电商业内人都知道&#xff0c;商品描述本地化是个长期痛点。去年帮深圳某3C卖家做德语站优化时&#xff0c;他们团队用谷歌翻译直接生成的产品说明&#xff0c;把"防水等级IP68"译成了"可以带着游泳"&#xff0c;导致退货率激增2…

作者头像 李华