Wasp 0.13 到 0.14 迁移指南:schema.prisma 接管数据模型与全新的 AuthUser 访问 API

发布时间:2026/9/14 4:56:44
Wasp 0.13 到 0.14 迁移指南:schema.prisma 接管数据模型与全新的 AuthUser 访问 API Wasp 0.13 到 0.14 迁移指南schema.prisma 接管数据模型与全新的 AuthUser 访问 API【免费下载链接】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 仓库 web/versioned_docs/version-0.14/migration-guide.md 整理。Wasp 0.14.0 是一次包含破坏性变更的里程碑版本它把数据库模型的定义权从.wasp文件移交给了 Prisma 原生的schema.prisma文件同时用一套更简单、类型更完整的user.identitiesAPI 取代了旧的getUsername、getEmail等辅助函数。读完本文你将掌握从 0.13.x 平滑升级到 0.14.x 的完整步骤版本与 tsconfig 更新、实体迁移到 schema.prisma、auth 字段访问代码的逐个改写以及最后的数据库迁移。:::note 你还在 0.11.X 或更早版本吗 本指南只覆盖0.13.X → 0.14.X的迁移。如果你是从 0.11.X 或更早版本迁移请先阅读 0.11.X 到 0.12.X 的迁移指南。 :::0.14.0 带来了什么直接使用 Prisma Schema 文件在 0.14.0 之前用户必须在.wasp文件中用entity ... {psl ... psl}语法定义实体Wasp 再基于这些定义生成schema.prisma文件。这种做法存在一些限制用户无法使用部分高级 Prisma 特性。0.14.0 起Wasp 把schema.prisma文件直接暴露给用户。你现在直接在schema.prisma文件中定义实体Wasp 使用它来生成数据库 schema 和 Prisma Clientschema.prisma文件成为数据库 schema 的唯一事实来源source of truth。简单来说原来写在.wasp文件里的实体现在全部搬到schema.prisma文件里.wasp文件只负责应用级配置。迁移前后对比wasp titlemain.wasp app myApp { wasp: { version: ^0.13.0 }, title: MyApp, db: { system: PostgreSQL }, }entity User {psl id Int id default(autoincrement()) tasks Task[] psl} entity Task {psl id Int id default(autoincrement()) description String isDone Boolean userId Int user User relation(fields: [userId], references: [id]) psl} wasp titlemain.wasp app myApp { wasp: { version: ^0.14.0 }, title: MyApp, } prisma titleschema.prisma datasource db { provider postgresql url env(DATABASE_URL) } generator client { provider prisma-client-js } model User { id Int id default(autoincrement()) tasks Task[] } model Task { id Int id default(autoincrement()) description String isDone Boolean userId Int user User relation(fields: [userId], references: [id]) } 可以看到db.system配置从.wasp文件中消失改由datasource块的provider决定entity关键字变成 Prisma 的model关键字psl ... psl包裹标签被移除。更好的 Auth 用户 APIWasp 引入了更简单的 API 来访问用户认证字段如username、email、isEmailVerified。你不再需要每次访问用户名时调用辅助函数也不需要做额外的类型体操来获得正确的类型。新的 API 把认证数据统一放在user.identities.provider上每个启用过的认证方法对应identities上的一个对象且类型是完整的、可推导的。如何迁移要把应用迁移到 Wasp 0.14.x必须完成以下三件事更新main.wasp中的版本号并更新tsconfig.json把实体迁移到新的schema.prisma文件更新访问用户字段的代码。1. 更新版本号与tsconfig.json先从简单的开始把 Wasp 文件中的version字段更新为^0.14.0app MyApp { wasp: { // highlight-next-line version: ^0.14.0 }, }为了确保项目在 Wasp 0.14.0 下正常工作你还必须更新tsconfig.json文件。如果你从未修改过项目里的tsconfig.json大多数用户属于这种情况直接用下面新版本的内容整体替换即可如果你修改过tsconfig.json建议以新版本文件为基底重新应用你自己的改动。新版本的tsconfig.json如下注意它只用于 Wasp 的 IDE 支持不会影响 TypeScript 编译器本身的行为// IMPORTANT // // This file is only used for Wasp IDE support. You can change it to configure // your IDE checks, but none of these options will affect the TypeScript // compiler. Proper TS compiler configuration in Wasp is coming soon :) { compilerOptions: { module: esnext, target: esnext, // Were bundling all code in the end so this is the most appropriate option, // its also important for autocomplete to work properly. moduleResolution: bundler, // JSX support jsx: preserve, strict: true, // Allow default imports. esModuleInterop: true, lib: [dom, dom.iterable, esnext], allowJs: true, typeRoots: [ // This is needed to properly support Vitest testing with jest-dom matchers. // Types for jest-dom are not recognized automatically and Typescript complains // about missing types e.g. when using toBeInTheDocument and other matchers. node_modules/testing-library, // Specifying type roots overrides the default behavior of looking at the // node_modules/types folder so we had to list it explicitly. // Source 1: https://www.typescriptlang.org/tsconfig#typeRoots // Source 2: https://github.com/testing-library/jest-dom/issues/546#issuecomment-1889884843 node_modules/types ], // Since this TS config is used only for IDE support and not for // compilation, the following directory doesnt exist. We need to specify // it to prevent this error: // https://stackoverflow.com/questions/42609768/typescript-error-cannot-write-file-because-it-would-overwrite-input-file outDir: .wasp/phantom } }几个关键配置点的用途值得留意moduleResolution: bundlerWasp 最终会打包所有代码这是最合适的解析策略同时对 IDE 自动补全至关重要typeRoots显式列出node_modules/testing-library与node_modules/types前者是为了让 Vitest 测试中的 jest-dom 匹配器如toBeInTheDocument有类型定义后者是因为指定 typeRoots 会覆盖默认的types查找行为必须手动补上outDir: .wasp/phantom这个目录实际上不存在该配置仅用于 IDE 支持而非编译指定它是为了避免 TypeScript 报 Cannot write file because it would overwrite input file 之类的错误。2. 迁移到新的schema.prisma文件要使用新的schema.prisma文件需要把实体从.wasp文件移到schema.prisma文件中。按下面六个步骤操作① 创建新的schema.prisma文件在项目根目录创建一个名为schema.prisma的新文件. ├── main.wasp ... // highlight-next-line ├── schema.prisma ├── src ├── tsconfig.json └── vite.config.ts② 添加datasource块该块指定数据库类型和连接 URLprisma titleschema.prisma datasource db { provider sqlite url env(DATABASE_URL) } prisma titleschema.prisma datasource db { provider postgresql url env(DATABASE_URL) } provider只能是postgresql或sqliteWasp 目前只支持这两种数据库url必须设置为env(DATABASE_URL)这样 Wasp 才能从环境变量注入数据库 URL。③ 添加generator块该块指定 Wasp 使用的 Prisma Client 生成器prisma titleschema.prisma datasource db { provider sqlite url env(DATABASE_URL) }// highlight-start generator client { provider prisma-client-js } // highlight-end prisma titleschema.prisma datasource db { provider postgresql url env(DATABASE_URL) }// highlight-start generator client { provider prisma-client-js } // highlight-end provider必须设置为prisma-client-js。④ 把实体移动到schema.prisma文件prisma titleschema.prisma datasource db { provider sqlite url env(DATABASE_URL) }generator client { provider prisma-client-js } // There are some example entities, you should move your entities here // highlight-start model User { id Int id default(autoincrement()) tasks Task[] } model Task { id Int id default(autoincrement()) description String isDone Boolean userId Int user User relation(fields: [userId], references: [id]) } // highlight-end prisma titleschema.prisma datasource db { provider postgresql url env(DATABASE_URL) }generator client { provider prisma-client-js } // There are some example entities, you should move your entities here // highlight-start model User { id Int id default(autoincrement()) tasks Task[] } model Task { id Int id default(autoincrement()) description String isDone Boolean userId Int user User relation(fields: [userId], references: [id]) } // highlight-end 移动实体时需要把entity改成model并移除psl和psl标签。如果.wasp文件里原来是这样entity Task {psl // Stays the same psl}那么在schema.prisma文件中它应该长这样model Task { // Stays the same }⑤ 从 Wasp 文件中移除app.db.system字段数据库系统现在在schema.prisma文件中配置.wasp文件中不再需要这个字段app MyApp { // ... db: { // highlight-next-line system: PostgreSQL, } }⑥ 把 Prisma preview features 配置迁移到schema.prisma文件如果你没有使用任何 Prisma preview features可以跳过这一步。如果.wasp文件里原来是这样app MyApp { // ... db: { // highlight-start prisma: { clientPreviewFeatures: [postgresqlExtensions] dbExtensions: [ { name: hstore, schema: myHstoreSchema }, { name: pg_trgm }, { name: postgis, version: 2.1 }, ] } // highlight-end } }迁移后变成datasource db { provider postgresql url env(DATABASE_URL) // highlight-next-line extensions [hstore(schema: myHstoreSchema), pg_trgm, postgis(version: 2.1)] } generator client { provider prisma-client-js // highlight-next-line previewFeatures [postgresqlExtensions] }也就是说clientPreviewFeatures数组对应generator块里的previewFeatures而dbExtensions数组则对应datasource块里的extensions配置项的语法也从 Wasp 风格的命名对象改写为 Prisma 原生的扩展调用语法。从仓库源码印证schema.prisma 成为事实来源仓库中 examples/ask-the-documents/schema.prisma 正是这一模式的现实案例它在datasource块里声明了extensions [pgvector(map: vector)]在generator块里声明了previewFeatures [postgresqlExtensions]并用Unsupported(vector(1536))定义向量字段——这些能力在 0.13 的.wasp实体语法下是无法直接表达的。其对应的 main.wasp.ts 中则只保留了app({...})与spec: [...]应用级配置query/action/route 等不再包含任何实体定义。这印证了 0.14 的设计目标凡是合法的 Prisma schema 代码在 Wasp 中都能直接用。关于datasource、generator、model、enum块的详细规则如 provider 仅支持postgresql/sqlite、url必须为env(DATABASE_URL)、必须存在prisma-client-jsgenerator、支持额外的 enum 块并在服务端/客户端通过prisma/client导入枚举值等可以阅读当前文档 web/docs/data-model/prisma-file.md 与 0.14 版本的 web/versioned_docs/version-0.14/data-model/prisma-file.md。迁移完代码后剩下的事情就是迁移数据库了。为了避免类型错误最好在迁移完其余代码之后再处理数据库迁移。继续往下读我们会在迁移指南的最后一步提醒你执行数据库迁移。3. 迁移用户认证字段的访问方式为了得到新的更简单 APIWasp 做了一些破坏性变更。请按下面五个步骤逐个迁移① 用user.identities.username.id替换getUsername辅助函数如果你没有在代码中使用getUsername可以跳过这一步。这个辅助函数已经变更它不再适用于你在页面 props 或context中收到的user对象。你需要把它替换为user.identities.username.id。tsx titlesrc/MainPage.tsx import { getUsername, AuthUser } from wasp/authconst MainPage ({ user }: { user: AuthUser }) { const username getUsername(user) // ... } ts titlesrc/tasks.ts import { getUsername } from wasp/auth export const createTask: CreateTask... async (args, context) { const username getUsername(context.user) // ... } tsx titlesrc/MainPage.tsx import { AuthUser } from wasp/authconst MainPage ({ user }: { user: AuthUser }) { const username user.identities.username?.id // ... } ts titlesrc/tasks.ts export const createTask: CreateTask... async (args, context) { const username context.user.identities.username?.id // ... } 注意迁移后的写法多了可选链?.如果用户没有用用户名方式注册identities.username就是null直接访问.id会报错。参考 web/versioned_docs/version-0.14/auth/entities/_username-data.md 中定义的usernameIdentity.id这就是用户名方式下username的取值。② 用user.identities.email.id替换getEmail辅助函数如果你没有在代码中使用getEmail可以跳过这一步。tsx titlesrc/MainPage.tsx import { getEmail, AuthUser } from wasp/authconst MainPage ({ user }: { user: AuthUser }) { const email getEmail(user) // ... } ts titlesrc/tasks.ts import { getEmail } from wasp/auth export const createTask: CreateTask... async (args, context) { const email getEmail(context.user) // ... } tsx titlesrc/MainPage.tsx import { AuthUser } from wasp/authconst MainPage ({ user }: { user: AuthUser }) { const email user.identities.email?.id // ... } ts titlesrc/tasks.ts export const createTask: CreateTask... async (args, context) { const email context.user.identities.email?.id // ... } ③ 用user.identities.provider.value替换对providerData的访问如果你没有使用providerData对象中的任何数据可以跳过这一步。把provider替换为提供者名称例如username、email、google、github等把value替换为你要访问的字段例如isEmailVerified。tsx titlesrc/MainPage.tsx import { findUserIdentity, AuthUser } from wasp/authfunction getProviderData(user: AuthUser) { const emailIdentity findUserIdentity(user, email) // We needed this before check for proper type support return emailIdentity isEmailVerified in emailIdentity.providerData ? emailIdentity.providerData : null } const MainPage ({ user }: { user: AuthUser }) { const providerData getProviderData(user) const isEmailVerified providerData ? providerData.isEmailVerified : null // ... } tsx titlesrc/MainPage.tsx import { AuthUser } from wasp/authconst MainPage ({ user }: { user: AuthUser }) { // The email object is properly typed, so we can access isEmailVerified directly const isEmailVerified user.identities.email?.isEmailVerified // ... } 迁移后的代码不再需要isEmailVerified in providerData这种运行时检查——email identity 对象本身携带完整的类型定义可以直接访问isEmailVerified。这正是 0.14 更好的 Auth 用户 API 的核心收益类型推导取代手工检查。邮箱 identity 上可用的字段可参考 web/versioned_docs/version-0.14/auth/entities/_email-data.mdid、isEmailVerified、emailVerificationSentAt、passwordResetSentAtGoogle identity 字段可参考 web/versioned_docs/version-0.14/auth/entities/_google-data.md。④ 直接在 user 对象上使用getFirstProviderUserId如果你没有在代码中使用getFirstProviderUserId可以跳过这一步。把getFirstProviderUserId(user)替换为user.getFirstProviderUserId()。tsx titlesrc/MainPage.tsx import { getFirstProviderUserId, AuthUser } from wasp/authconst MainPage ({ user }: { user: AuthUser }) { const userId getFirstProviderUserId(user) // ... } ts titlesrc/tasks.ts import { getFirstProviderUserId } from wasp/auth export const createTask: CreateTask... async (args, context) { const userId getFirstProviderUserId(context.user) // ... } tsx titlesrc/MainPage.tsx import { AuthUser } from wasp/authconst MainPage ({ user }: { user: AuthUser }) { const userId user.getFirstProviderUserId() // ... } ts titlesrc/tasks.ts export const createTask: CreateTask... async (args, context) { const userId user.getFirstProviderUserId() // ... } getFirstProviderUserId会返回找到的第一个提供者用户 ID例如用户用 email 注册就返回 email用 Google 注册就返回 Google ID。这在支持多认证方式、且只需要任意一个能标识用户的 ID时非常有用。⑤ 用对user.identities.provider的检查替换findUserIdentity如果你没有在代码中使用findUserIdentity可以跳过这一步。不再需要用findUserIdentity获取 identity 对象直接检查identities对象上是否存在对应的 identity 即可。tsx titlesrc/MainPage.tsx import { findUserIdentity, AuthUser } from wasp/authconst MainPage ({ user }: { user: AuthUser }) { const usernameIdentity findUserIdentity(user, username) if (usernameIdentity) { // ... } } ts titlesrc/tasks.ts import { findUserIdentity } from wasp/auth export const createTask: CreateTask... async (args, context) { const usernameIdentity findUserIdentity(context.user, username) if (usernameIdentity) { // ... } } tsx titlesrc/MainPage.tsx import { AuthUser } from wasp/authconst MainPage ({ user }: { user: AuthUser }) { if (user.identities.username) { // ... } } ts titlesrc/tasks.ts export const createTask: CreateTask... async (args, context) { if (context.user.identities.username) { // ... } } 新 API 的完整形态迁移完成后你拿到的AuthUser对象会同时包含业务字段与认证字段你自定义的User字段位于顶层认证相关字段统一放在identities对象下每种认证方法一个数据对象。例如同时启用了 email 与 Google 认证时const user { // 自定义 User 数据 id: cluqsex9500017cn7i2hwsg17, address: Some address, // 认证相关数据 identities: { email: { id: userapp.com, isEmailVerified: true, emailVerificationSentAt: 2024-04-08T10:06:02.204Z, passwordResetSentAt: null, }, google: null, }, }使用前提务必牢记如果用户没有用某种方式注册对应 identity 就是null访问前必须先判空if (user.identities.google ! null) { const userId user.identities.google.id // ... }如果支持多种认证方式通常需要先判断用户拥有哪个 identity 再访问其数据if (user.identities.email ! null) { const email user.identities.email.id // ... } else if (user.identities.google ! null) { const googleId user.identities.google.id // ... }更深层的机制是这些identities数据来自 Wasp 在后台自动创建的Auth、AuthIdentity、Session三个内部实体Auth通过userId连接业务用户UserAuthIdentity以providerNameproviderUserId联合主键存储各提供者的登录凭证Session负责保持登录态。当你需要从其他实体的关联查询中取出用户认证数据时要在 Prisma 查询里include这些关系并注意providerData可能包含哈希密码等敏感信息返回给客户端前应排除。这些细节在当前文档 web/docs/auth/entities/entities.md 和 0.14 版本对应的 web/versioned_docs/version-0.14/auth/entities/entities.md 中有完整说明。6. 迁移数据库最后运行 Wasp CLI重新生成 Prisma Clientwasp db migrate-dev该命令会根据schema.prisma文件生成 Prisma Client。建议在完成上述所有代码迁移之后再执行这一步以避开迁移过程中产生的类型错误。迁移完成这样就可以了现在你应该可以用新的 Wasp 0.14.0 运行你的应用了。我们建议通读更新后的 Accessing User Data 章节以更好地理解新 API。关于schema.prisma文件与 Wasp 的协作方式Wasp 如何读取该文件生成数据库 schema 与 Prisma Client可继续阅读 web/versioned_docs/version-0.14/data-model/prisma-file.md 或当前的 web/docs/data-model/prisma-file.md。【免费下载链接】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),仅供参考