vue-vben-admin 表单体系迁移实战从 Zod 3 到 Zod 4 与 TanStack Form【免费下载链接】vue-vben-adminA modern vue admin panel built with Vue3, Shadcn UI, Vite, TypeScript, and Monorepo. Its fast!项目地址: https://gitcode.com/GitHub_Trending/vu/vue-vben-admin本篇技术指南系统讲解 vue-vben-admin 将表单校验体系从 Zod 3 升级到 Zod 4、并将内部表单引擎从 vee-validate 替换为 TanStack Form 的完整迁移方案。文章覆盖依赖变更、兼容性边界、Form UI API 的新增与废弃、规则注册、Codemod 迁移工具、Zod 4 关键行为变化以及测试验收矩阵读者可据此完成业务表单的无感升级同时掌握 Vben 表单层业务 API 稳定、实现 API 解耦的设计思路。迁移概览升级了什么保住了什么本次迁移的核心理念是Vben 业务层 API 保持稳定实现细节被隔离在公共边界之外。也就是说业务代码中通过useVbenForm书写的表单定义、FormSchema字段结构、componentField插槽绑定形态等在迁移后依然可用而 vee-validate 相关的内部表单 API 则从公共导出中被移除。从源码结构看表单核心实现集中在 packages/core/ui-kit/form-ui其中 use-vben-form.ts 负责对外暴露useVbenFormform-runtime.ts 内部直接调用useForm来自tanstack/vue-form这印证了迁移后表单引擎已切换为 TanStack Form 的事实。依赖变更迁移前后的依赖对照如下区域迁移前迁移后Schema 校验zod^3.25.76zod^4.4.3默认值生成zod-defaults0.1.3zod-defaults^0.2.3表单引擎vee-validate^4.15.1tanstack/vue-form^1.33.2Zod 适配器vee-validate/zod^4.15.1移除TanStack Form 原生支持 Standard Schema迁移完成后源码、package 清单与 lockfile 中都不能再出现vee-validate或vee-validate/zod的依赖。在 packages/core/ui-kit/form-ui/package.json 中可以看到当前依赖仅保留tanstack/vue-form、zod、zod-defaults均以catalog:形式引用 workspace 统一版本这与文档描述的迁移目标状态一致。兼容性边界迁移后仍受支持的 Vben API以下 Vben 公开 API 在迁移后保持不变useVbenForm(options)返回[Form, formApi]既有FormApi的取值、重置、校验、提交、schema 更新与组件 ref 获取方法既有FormSchema字段、dependencies、已废弃的valueFormat以及数组 schema 结构应用适配器与重新导出的z命名空间既有的componentField插槽及其绑定形态。其中formApi.form现在是与库无关的FormContextApi它暴露 values、errors、meta、set/reset/validate/submit 方法与数组操作但不会泄漏 vee-validate 或裸 TanStack 的泛型细节。这一点在 types.ts 的FormContextApi接口中有完整定义reset、submit、clearValidation、useValues、useFieldValue、useFieldValues、useFieldError、pushFieldValue、removeFieldValue、getFieldError、isFieldValid、setFieldValue、setValues等均在该接口上。新代码统一使用reset、submit、validateAndSubmit、clearValidation旧的resetForm、submitForm、validateAndSubmitForm、resetValidate作为转发别名保留并标记废弃开发环境每个名字只告警一次生产环境静默。在 form-api.ts 中可以看到这些废弃方法如resetForm、submitForm、validateAndSubmitForm、resetValidate都通过 deprecation.ts 的warnDeprecatedOnce输出一次性告警后转发到对应的新方法。Form UI API 变更详解新增 APIAPI类型/位置说明dependencies.resolve(context)FormItemDependenciesResolve根据声明的triggerFields求值一次完整的动态补丁并原子提交context 包含只读的values、actions、controller与感知行数据的schemauseValues()FormContextApi订阅全部表单值仅在需要全表单响应式时使用useFieldValue(fieldName)FormContextApi只订阅单个字段值不响应无关字段useFieldValues(fieldNames)FormContextApi订阅一组已声明字段的值useFieldError(fieldName)FormContextApi只订阅单个字段错误避免消费整个错误对象getRawValues()FormApi返回 codec/遗留格式化之前的独立表单值快照formatValues(rawValues)FormApi对传入的原始快照执行统一格式化管线getValueSnapshot()FormApi返回{ rawValues, values }其中values为TSubmitValuesasyncDebounceMsFormFieldOptions配置 TanStack Field 异步校验防抖changeEventFallbackFormCommonConfig/ 适配器配置为只发change不发update:*的遗留组件启用回退默认false关于dependencies.resolve其返回的补丁可以包含if、show、disabled、required、rules、componentProps、help、renderComponentContent。省略rules表示保留静态规则返回rules: null则禁用静态规则。在 types.ts 中FormItemDependenciesResolve通过resolve?: never与遗留回调字段互斥FormItemDependenciesLegacytypes.ts#L429-L473则保留了componentProps/disabled/if/required/rules/show/trigger并全部标记deprecated。变更的 APIAPI迁移前迁移后提交回调handleSubmit(values)handleSubmit(values, rawValues)第一个参数是格式化后的值第二个是对应的只读原始快照单参数函数依旧合法值变化回调handleValuesChange(values, fieldsChanged)handleValuesChange(rawValues, fieldsChanged, getFormattedValues)格式化是惰性的不调用第三个参数就不会产生克隆/转换开销字段校验触发四个validateOn*布尔量validateOn?: readonly (blur \| change)[]提交时始终校验change 事件兼容disabledOnChangeListener: false开启回退changeEventFallback: true以正向语义开启回退顶层渲染回调componentProps(values, actions, ctx)、help(values, actions, ctx)、renderComponentContent(values, actions, ctx)只接收轻量FormSchemaContext依赖值的行为迁移到dependencies.resolvevalidateAndSubmit()重复的低层校验/滚动处理提交过程中可能再次校验委托给规范validate()与共享提交逻辑非法表单不提交getValues()隐式返回转换后的值返回 codec 编码的TSubmitValues无 codec 时保留遗留格式化移除的 API移除的 API替代方案FormValidationOptionsvalidate()与validateField(fieldName)不再接受选项force/silent/validated-only校验模式移除因为 vee 的这三种模式在 TanStack 运行时没有对应语义validateOnBlur/validateOnChange/validateOnInput/validateOnModelUpdate使用formFieldProps.validateOninput 与 model update 由change统一表示disabledOnChangeListener使用正向的changeEventFallbackdisabledOnInputListenerinput 监听不再自动绑定需要时显式提供componentProps.onInput顶层 schema 渲染函数中的values/actions参数使用FormSchemaContext依赖值的行为迁移到dependencies.resolve废弃但受支持dependencies.if/show/disabled/required/rules/componentProps/trigger本版本仍然兼容但每个回调都标记deprecated并在开发环境输出一次告警若两种语法绕过类型联合同时出现resolve优先resetForm、submitForm、resetValidate、validateAndSubmitForm继续转发到规范方法FormActions作为FormContextApi的废弃别名保留types.ts#L215-L217setupVbenForm({ defineRules })仍然支持同名规则时rules优先重新导出的z、componentField插槽、emptyStateValue保持不变。内部行为变化字段组件使用细粒度的值/错误选择器完整错误聚合不再位于常规输入路径上异步校验通过 Vben 自己的 generation 机制丢弃过期 Promise不再读取 TanStack 私有的 AbortController 或 meta 字段新老 dependencies 共用同一个原子执行器过期异步结果不会覆盖新状态新代码使用一个表单级 codec 原子地编码完整对象遗留的数组转字符串、区间映射与 schemavalueFormat保持兼容但已废弃。类型化值与插槽应用适配器固定 UI 组件映射业务值形状作为唯一泛型暴露interface AccountFormValues { email: string; nickname: string; } const [Form, formApi] useVbenFormAccountFormValues({ handleSubmit(values) { return addAccount(values); }, schema: [ { component: Input, fieldName: email }, { component: Input, fieldName: nickname }, ], });TValues会贯穿VbenFormProps、FormSchema、FormApi、FormContextApi、值 API、提交/变化回调、选择器与动态 schema 回调。返回的Form组件也暴露类型化插槽已知字段插槽使用对应的值类型用于field.state.value与componentField.modelValue而所有 field/default/action 插槽都收到完整的values与对应的formApi。未声明TValues的遗留表单则保留任意插槽名与宽泛 props。在 use-vben-form.ts 中可以看到useVbenForm提供了两条重载未声明泛型时返回FormValues形态声明后返回精确的TValues/TSubmitValues形态二者都返回[VbenFormComponent, ExtendedFormApi]元组。新老规则注册新代码使用rulessetupVbenForm({ rules: { required(value, _params, context) { const isEmpty value undefined || value null || value || (Array.isArray(value) value.length 0); return isEmpty ? ${context.label} is required : true; }, }, });遗留的defineRules选项转发到同一个注册表setupVbenForm({ defineRules: { required: legacyRequiredRule, }, });遗留运行时用法在开发环境按废弃键每个输出一次告警生产环境无告警。若两个选项定义了同名规则rules优先。FormActions类型保留为FormContextApi的废弃别名编辑器会报告类型层面的废弃因为纯类型使用无法触发运行时告警。从源码看config.ts 的setupVbenForm在收到defineRules时会输出废弃告警而 rule-registry.ts 内部维护一个Mapstring, FormRuleValidatorregisterFormRules按名字注册校验器、getFormRule按名字取出这正是rules优先与同名规则覆盖的底层实现。运行 Codemod在干净的 Git worktree 上对每个受影响的 tsconfig 运行固定版本工具npx --yes zod-v3-to-v41.21.3 path/to/tsconfig.json该工具会就地修改.ts、.tsx、.vue文件没有 dry-run 模式运行后务必检查git diff。需要注意Codemod 主要识别直接的zod导入。通过vben/common-ui或应用适配器获得z的 schema 需要人工复查尤其是构造函数错误、字符串格式与动态 refinement 消息。Zod 4 变更要点统一的错误参数用error取代required_error与invalid_type_errorconst count z.number({ error: (issue) issue.input undefined ? Count is required : Count must be a number, });动态 refinement 消息应使用error(issue)回调而不是把返回 params 的函数作为.refine()的第二个参数传入。字符串格式与错误优先使用顶层格式 schemaz.email(Invalid email); z.url(Invalid URL); z.uuid(Invalid UUID);校验细节从ZodError.issues读取旧的.errors属性已移除。默认值与可空性Zod 4 的 defaults 在输入为undefined时可能立即返回。应基于实际 parse 行为审查.default().optional()而不是依赖内部类型名。Vben 初始值采用如下优先级schema 显式defaultValueZod.default()Zod 4 兼容的zod-defaults组件空状态约定必填标记由 schema 是否接受undefined推导。Wrapper、Refine、Transform 与 Coerce不要读取_def、_zod.def或typeName改用公开的.unwrap()API 与公开的 pipe 输入交集默认值委托给 Zod 4 兼容的zod-defaults包。Standard Schema 校验不会把 transform/coerce 输出写回 TanStack Form 状态。提交载荷转换应使用表单级 codec当确实需要 transform 后的 schema 输出时在 codec 的encode边界内显式调用parseAsync。还需审查这些变化z.record()必须指定键与值 schemaz.enum()取代原nativeEnum的使用场景number 的 integer、Infinity 与 finite 行为object 的严格性、merge 与未知键交集合并冲突coerce 输入类型默认unknownZod 3 类型如ZodEffects、ZodTypeAny、AnyZodObject被移除表单引擎行为formFieldProps.validateOn接受blur与change默认两者都开启提交时始终校验字段asyncDebounceMs配置 TanStack Field 异步防抖。四个 vee 风格的validateOn*布尔量与force/silent/validated-only模式已移除。shadcn 表单原语现在使用 Vben 自有的字段上下文。Label、control、description 与 message 继续提供 id、aria-invalid、aria-describedby、touched、dirty、valid 与 error 状态。clearValidation(fieldNames?)会推进 Vben 的 validator generation 并清除公开错误状态不依赖 TanStack 私有 AbortController之后才完成的 Promise 会被当作过期结果丢弃。省略fieldNames时覆盖所有已注册字段以及所有已有错误的字段。该实现位于 form-runtime.ts 附近与 form-api.ts 的clearValidation转发对应。dependencies.resolve(context)是推荐 API一次求值、原子提交一个动态状态补丁过期异步结果整体丢弃遗留的if/show/disabled/required/rules/componentProps/trigger回调通过同一规范化执行器受支持但标记deprecated并在开发环境输出一次告警。两类 API 都只响应声明的triggerFields。其实现位于 dependencies.ts通过dependencyEvaluationId代数编号机制保证只有最新一次求值的结果会被提交。handleValuesChange(rawValues, fieldsChanged, getFormattedValues)接收只读的TFormValues仅当调用第三个参数时才执行 codec 或遗留格式化getRawValues()返回表单值getValues()返回TSubmitValues两者都需要时使用getValueSnapshot()handleSubmit(values, rawValues)在提交时同时收到两种形态。遗留的数组转字符串、区间映射与 schemavalueFormat保持兼容但已废弃。数组字段继续使用 TanStack 的 push/remove 操作与稳定行标识。测试与验收矩阵迁移必需的测试覆盖包括Zod defaults、optional、nullable、intersection、pipe、transform、coerce 与 errors运行时值、选择器、reset、手动错误、校验与异步校验字段绑定、blur/change 触发、错误消息、ARIA、dependencies 与数组新老 API 等价性、告警去重、生产环境静默与类型别名完整useVbenForm生命周期、提交、handleValuesChange、submit-on-change 与异步竞态处理验收标准零 TypeScript 错误、零构建错误、全部测试通过、浏览器无未处理错误、修改文件通过格式化与 lint、源码不再依赖 vee 或 Zod 私有结构。仓库中 form-ui 的测试目录 覆盖了表单集成、类型、字段节点名与性能基准等维度可作为验收矩阵的参考基线。迁移清单速览更新依赖zod^4.4.3、zod-defaults^0.2.3、tanstack/vue-form^1.33.2删除vee-validate与vee-validate/zod在干净 worktree 上对每个受影响 tsconfig 运行npx --yes zod-v3-to-v41.21.3 tsconfig随后检查git diff人工复查通过vben/common-ui或适配器获取z的 schema构造函数错误、字符串格式、动态 refinement将required_error/invalid_type_error迁移为error将.refine(fn, params)迁移为error(issue)回调将validateOn*布尔量合并为formFieldProps.validateOndisabledOnChangeListener改为changeEventFallback: true将顶层componentProps/help/renderComponentContent中依赖值的逻辑迁移到dependencies.resolve(context)将resetForm/submitForm/validateAndSubmitForm/resetValidate替换为reset/submit/validateAndSubmit/clearValidation需要同时取格式化前后值时优先使用getValueSnapshot()提交时使用handleSubmit(values, rawValues)将defineRules迁移到rules同名规则由rules优先校验提交载荷转换统一走表单级codec不再依赖 transform/coerce 写回表单状态按验收矩阵补齐测试确保零 TS/构建错误、测试全绿、无 vee 与 Zod 私有结构依赖。【免费下载链接】vue-vben-adminA modern vue admin panel built with Vue3, Shadcn UI, Vite, TypeScript, and Monorepo. Its fast!项目地址: https://gitcode.com/GitHub_Trending/vu/vue-vben-admin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考