ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

从 Wasp TS Config 迁移到 Wasp Spec:Wasp 0.24 配置体系全面升级指南

从 Wasp TS Config 迁移到 Wasp Spec:Wasp 0.24 配置体系全面升级指南 从 Wasp TS Config 迁移到 Wasp SpecWasp 0.24 配置体系全面升级指南【免费下载链接】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 官方迁移文档wasp-ts-config.md为主线系统讲解 Wasp 0.24 将类式TS Confignew App(...)退休、转向函数式Wasp Specapp({ ... })的完整迁移路径。文章覆盖新旧 API 的全量映射、参考导入reference imports、多文件拆分、六个顶层配置项的写法变化并给出可直接落地的package.json、tsconfig.wasp.json、tsconfig.src.json修改清单与main.wasp.ts重写示例帮助开发者把存量项目平滑升级到 Wasp Spec同时结合本仓库源码constructors.ts、waspSpec.ts与真实示例项目TodoApp、Kitchen Sink讲透底层实现。背景为什么 TS Config 会被 Wasp Spec 取代Wasp 最早以Wasp DSLmain.wasp文件声明应用配置。后来引入的TS Config是配置 Wasp 的第一代 TypeScript 方案它采用类式 API在main.wasp.ts中通过new App(...)创建实例再以app.page(...)、app.query(...)这类可变方法调用注册各类声明依赖的包名为wasp-config。从Wasp 0.24开始TS Config 被正式退休取而代之的是 Wasp Spec一种函数式 API只需调用一次app({ ... })把所有页面、路由、查询、操作等统一放在spec属性中列出依赖包更名为wasp.sh/spec。用一句话概括两者差异维度TS Config旧Wasp Spec新创建应用new App(name, { ... })app({ name, ..., spec: [...] })配置应用app.auth(...)、app.server(...)、app.client(...)、app.db(...)、app.emailSender(...)、app.webSocket(...)全部收敛为app({ ... })对象的键auth、server、client、db、emailSender、webSocket添加规格app.route(...)、app.query(...)、app.action(...)等链式调用app({ spec: [route(...), query(...), action(...)] })引用代码导入对象{ import, from }import { ... } from ./src/... with { type: ref };包名wasp-configwasp.sh/spec从源码层面看新 Spec 的构造函数位于 constructors.ts其中app只是把传入的配置对象原样返回export function app(config: AppConfig): App { return config; }而page、route、query等则各自构造带kind标签的规格对象例如page()返回{ kind: page, component, ...config }。这意味着Wasp Spec 本质上是用普通 TypeScript 值描述应用结构Wasp 编译器读取main.wasp.ts的默认导出即可生成应用。正在从 Wasp 0.23 升级到 0.24下面的转换是机械性的可以让 LLM 代劳大部分工作。迁移指南中提供了一段可复制的 Prompt它把本文、Wasp Spec 文档以及共享迁移步骤打包在一起交给 Agent。配置转换完成后回到迁移指南完成剩余的共享步骤即可。新特性一参考导入Reference Imports在 TS Config 中你只能用导入对象{ import, from }来引用自己的代码。Wasp Spec 额外支持参考导入用常规import语法导入值并直接把它传给规格构造函数。const mainPage app.page(MainPage, { component: { importDefault: MainPage, from: src/MainPage }, }); app.query(getTasks, { fn: { import: getTasks, from: src/queries }, });import MainPage from ./src/MainPage with { type: ref }; import { getTasks } from ./src/queries with { type: ref }; export default app({ // ... spec: [ route(MainRoute, /, page(MainPage)), query(getTasks), ], });注意导入语句末尾的with { type: ref }这是告诉 Wasp这是一个源码引用的关键语法。渐进迁移ref(...)辅助函数仍然可用如果你不想一次性全部切换旧式导入对象依然可以通过ref(...)辅助函数继续工作从而渐进式迁移。参见 Wasp Spec 文档——引用应用代码中支持的写法及其限制import { ref } from wasp.sh/spec; export default app({ // ... spec: [ page(ref({ importDefault: MainPage, from: ./src/MainPage })), query(ref({ import: getTasks, from: ./src/queries })), // 用 alias 重命名具名导入 query(ref({ import: getTasks, alias: getAllTasks, from: ./src/queries })), ], });ref(...)中的from路径相对于调用它的*.wasp.ts文件且必须解析到项目src目录内。参考导入的已知限制从 Wasp Spec 文档可知参考导入有以下边界条件只能在*.wasp.ts文件中使用被引用的文件必须位于src目录内不能以export { X } from ./X with { type: ref }的形式再导出参考导入需先导入再导出不支持命名空间导入import * as something ... with { type: ref }请使用具名或默认导入。绝大多数 Wasp 应用不会触碰到这些限制因此官方推荐默认使用参考导入。新特性二多文件拆分Splitting into Multiple FilesTS Config 要求整个配置都存在于单一的main.wasp.ts中。而 Wasp Spec 允许把配置拆分到多个*.wasp.ts文件并在文件之间导入规格方便大型应用按模块组织例如在特性目录旁边放一个独立的auth.wasp.ts或cards.wasp.ts。每个特性文件导出自己的Specimport { page, route, type Spec } from wasp.sh/spec; import { LoginPage } from ./LoginPage with { type: ref }; import { SignupPage } from ./SignupPage with { type: ref }; export const authSpec: Spec [ route(SignupRoute, /signup, page(SignupPage)), route(LoginRoute, /login, page(LoginPage)), ];Spec类型标注让 TypeScript 能在该文件被并入main.wasp.ts之前就完成规格校验。然后在main.wasp.ts中导入并拼接import { app, page, route } from wasp.sh/spec; import { MainPage } from ./src/MainPage with { type: ref }; import { authSpec } from ./src/auth/auth.wasp; export default app({ name: todoApp, wasp: { version: ^0.24.0 }, title: ToDo App, head: [link relicon href/favicon.ico /], spec: [ route(MainRoute, /, page(MainPage, { authRequired: true })), authSpec, ], });本仓库的 Kitchen Sink 示例就是多文件拆分的完整范本它把authSpec、operationsSpec、jobsSpec、apisSpec、crudSpec、streamingSpec、chatSpec、lazyLoadingSpec、prerenderSpec、rpcTestsSpec分别放在src/features/与src/rpcTests/下的各特性文件中main.wasp.ts只负责汇总。详细说明见 Wasp Spec 文档——拆分 Spec。所有规格文件都应使用.wasp.ts扩展名这样才会被tsconfig.wasp.json收录并进行类型检查。变更详解App 与各类规格的写法对照App 与规格App and Specificationsimport { App } from wasp-config; const app new App(todoApp, { title: ToDo App, wasp: { version: ^0.24.0 }, }); const mainPage app.page(MainPage, { component: { importDefault: MainPage, from: src/MainPage }, }); app.route(MainRoute, { path: /, to: mainPage }); app.query(getTasks, { fn: { import: getTasks, from: src/queries }, entities: [Task], }); export default app;import { app, page, query, route } from wasp.sh/spec; import MainPage from ./src/MainPage with { type: ref }; import { getTasks } from ./src/queries with { type: ref }; export default app({ name: todoApp, title: ToDo App, wasp: { version: ^0.24.0 }, spec: [ route(MainRoute, /, page(MainPage)), query(getTasks, { entities: [Task] }), ], });对照要点旧的route用{ path, to }对象绑定路由新 API 中route(name, path, page(...))采用位置参数query的fn由导入对象变为参考导入的直接引用entities保留在第二参数中构造函数的实现细节可在 constructors.ts 中查看route返回{ kind: route, name, path, page, ...config }query返回{ kind: query, fn, ...config }。路由路径支持 React Router 的动态段/tasks/:id、可选段/photo/:id/edit?与通配段/files/*。APIhttpRoute改为位置参数app.apiNamespace(bar, { middlewareConfigFn: { import: barNamespaceMiddlewareFn, from: src/apis }, path: /bar, }); app.api(barBaz, { fn: { import: barBaz, from: src/apis }, auth: false, entities: [Task], httpRoute: { method: GET, route: /bar/baz }, });import { api, apiNamespace, app } from wasp.sh/spec; import { barBaz, barNamespaceMiddlewareFn } from ./src/apis with { type: ref }; export default app({ // ... spec: [ apiNamespace(/bar, { middlewareConfigFn: barNamespaceMiddlewareFn, }), api(GET, /bar/baz, barBaz, { auth: false, entities: [Task] }), ], });关键变化apiNamespace的path与middlewareConfigFn从平铺属性变为apiNamespace(path, { middlewareConfigFn })api的 HTTP 方法与路由从httpRoute对象提升为前两个位置参数api(GET, /bar/baz, barBaz, config)。method 支持GET、POST等具体方法也支持ALL表示任意方法从源码看api构造器签名是api(method, path, fn, config?)apiNamespace是apiNamespace(path, config)见 constructors.ts。Jobsperform被扁平化app.job(mySpecialJob, { executor: PgBoss, perform: { fn: { import: foo, from: src/jobs/bar }, executorOptions: { pgBoss: { retryLimit: 1 } }, }, entities: [Task], });import { app, job } from wasp.sh/spec; import { foo } from ./src/jobs/bar with { type: ref }; export default app({ // ... spec: [ job(foo, { executor: PgBoss, entities: [Task], performExecutorOptions: { pgBoss: { retryLimit: 1 } }, }), ], });变化要点Job 的实现函数foo直接作为job()的第一个参数传入旧的perform.executorOptions提升为顶层的performExecutorOptionsjob()构造器签名为job(fn, config)其中config必填executor可选schedule如{ cron: 0 * * * * }、entities、performExecutorOptions见 constructors.ts。Jobs 是跨服务器重启持久化的后台任务支持失败重试、延迟执行与 cron 定时调度。CRUDapp.crud(tasks, { entity: Task, operations: { getAll: {}, create: { overrideFn: { import: createTask, from: src/actions } }, }, });import { app, crud } from wasp.sh/spec; import { createTask } from ./src/actions with { type: ref }; export default app({ // ... spec: [ crud(tasks, Task, { getAll: {}, create: { overrideFn: createTask }, }), ], });CRUD 的构造器签名变为crud(name, entity, operations)名称与实体作为两个独立位置参数operations中每个操作可用空对象启用默认实现、用isPublic设为公开、或用overrideFn替换为自定义实现见 constructors.ts。顶层配置auth、server、client、db、emailSender、webSocket这些此前通过可变方法调用配置的项如今全部变成app({ ... })对象的键const app new App(todoApp, { title: ToDo App, wasp: { version: ^0.24.0 }, }); app.auth({ userEntity: User, methods: { google: {} }, onAuthFailedRedirectTo: /login, }); app.client({ rootComponent: { importDefault: App, from: src/App }, }); app.emailSender({ provider: SMTP, defaultFrom: { email: hiexample.com }, }); export default app;import { app } from wasp.sh/spec; import App from ./src/App with { type: ref }; export default app({ name: todoApp, title: ToDo App, wasp: { version: ^0.24.0 }, auth: { userEntity: User, methods: { google: {} }, onAuthFailedRedirectTo: /login, }, client: { rootComponent: App, }, emailSender: { provider: SMTP, defaultFrom: { email: hiexample.com }, }, // server、db、webSocket 同理作为顶层键 });从 waspSpec.ts 中App接口的定义可以看到这些顶层键的完整形态auth启用鉴权、server、client、db、emailSender、webSocket均为可选键另有必填的name内部应用名不能含空格、wasp.versionnpm 兼容的 SemVer 范围如^0.24.0、title浏览器标签页标题、head注入 HTMLhead的标签数组以及spec。值得一提的细节head数组中的每个条目会被渲染在 React 组件内因此字符串必须是合法的 JSX——自闭合标签必须以/结尾如meta ... /属性名需驼峰化如httpEquiv而非http-equiv同时由于已知的 React 缺陷script标签应避免defer改用async。迁移步骤从 TS Config 到 Wasp Spec 的完整操作清单在执行下面的wasp install之前请确保应用声明的 Wasp 版本为^0.24.0。迁移过程中 Wasp 会校验 Wasp Spec 支持文件包括package.json中必需的条目、tsconfig.wasp.json的选项以及tsconfig.src.json的排除项。第 1 步更新package.json依赖{ // ... devDependencies: { // ... wasp-config: file:.wasp/wasp-config } }{ // ... devDependencies: { // ... types/node: ^24.0.0, wasp.sh/spec: file:.wasp/spec } }保留既有依赖把wasp-config替换为wasp.sh/spec并新增types/node——types/node是必需的因为 Wasp Spec 运行在 Node.js 环境中。需要说明的是wasp.sh/spec并不存在于 npm 上它是 Wasp 为每个项目按需生成的包wasp install会安装应用依赖并生成这份 Spec 包。详细机制见 Wasp Spec 文档——wasp install。第 2 步更新tsconfig.wasp.json{ compilerOptions: { target: ES2022, module: esnext, moduleResolution: bundler, jsx: preserve, strict: true, isolatedModules: true, moduleDetection: force, skipLibCheck: true, allowJs: true, noEmit: true, lib: [ES2023] }, include: [**/*.wasp.ts, .wasp/out/types/spec] }该配置负责对所有*.wasp.ts规格文件做类型检查include同时纳入了 Wasp 生成到.wasp/out/types/spec的类型。第 3 步确保tsconfig.src.json排除 Wasp Spec 文件{ // ... include: [src], exclude: [**/*.wasp.ts] }让src目录的 TypeScript 项目不重复编译规格文件避免类型冲突。第 4 步运行wasp installwasp install安装依赖并生成或重新生成wasp.sh/spec包。当 Wasp 提示 Spec 需要重新生成时例如升级 Wasp 版本、执行wasp clean、删除node_modules都需要再次运行wasp install才能启动应用。第 5 步重写main.wasp.ts用单个app({ ... })调用取代new App(...)与所有app.*(...)方法调用把规格放进spec属性并更新 import对照上面的变更一览import { App } from wasp-config; const app new App(myApp, { title: My app, wasp: { version: ^0.24.0 }, });import { app } from wasp.sh/spec; export default app({ name: myApp, title: My app, wasp: { version: ^0.24.0 }, head: [link relicon href/favicon.ico /], spec: [ // ... ] });注意此前 Wasp 接受任意命名的*.wasp.ts文件而在 Wasp Spec 中入口文件必须命名为main.wasp.ts。其余配置仍可拆分到其他*.wasp.ts文件中。本仓库 TodoApp 示例是一个迁移后的标准形态name、wasp.version、title、head、auth均为顶层键页面路由routepage、查询query与操作action统一收进spec数组所有src/下的组件与函数都用with { type: ref }参考导入。第 6 步启动验证wasp start如果一切正确应用行为应当与迁移前完全一致。进阶技巧按环境切换配置由于 Wasp Spec 本身就是 TypeScript你可以在配置文件中读取环境变量实现一处配置、多环境生效。Wasp 会根据执行命令设置NODE_ENVwasp start以及wasp db migrate-dev等编译命令期间为developmentwasp build期间为production。const isProd process.env.NODE_ENV production; export default app({ //... emailSender: { provider: isProd ? SMTP : Dummy, defaultFrom: { email: hiexample.com }, }, });完成迁移后的收尾迁移完成后如果你还需要处理 Wasp 0.24 的共享迁移步骤如新增vitest依赖、将wasp/client/api从 Axios 切换到 ky 等请回到 0.23 → 0.24 迁移指南继续执行。想用 Agent 自动化迁移迁移指南提供了针对 TS Config 的完整可复制 Prompt。查阅所有可用配置选项的完整参考见 Wasp Spec 参考文档 以及其 API 类型定义 waspSpec.ts构造函数清单见 constructors.ts。想在迁移前观察新写法的工程实践可以直接研读仓库中的 TodoApp 与 Kitchen Sink 两个示例项目的main.wasp.ts及其拆分的多文件 Spec。【免费下载链接】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),仅供参考
返回列表