资讯动态

@sanity/schema 版本演进全解析:从 Schema Descriptor 序列化到引用类型内联提升

发布时间:2026/9/18 1:36:55 来源:尧图企业网站定制
sanity/schema 版本演进全解析从 Schema Descriptor 序列化到引用类型内联提升【免费下载链接】sanitySanity Studio – Rapidly configure content workspaces powered by structured content项目地址: https://gitcode.com/GitHub_Trending/sa/sanity本指南以仓库中 packages/sanity/schema/CHANGELOG.md 为脉络系统梳理 Sanity 内容建模核心包sanity/schema从 3.86 到 6.13 的关键演进Schema Descriptor描述符体系的建立、可移植文本Portable Text装饰器与国际化字段的保留、引用类型内联提升inline hoisting与 GROQ 类型提取以及验证系统的能力化改造。读完本文你将掌握这些版本变更背后的源码级实现原理、它们对 Studio 与 Content Lake 同步的影响以及升级到 6.x 需要注意的破坏性变更与依赖前提。一、版本脉络总览一条从类型编译走向可序列化 schema的演进线sanity/schema的定位从 README.md 可以概括为三件事Schema类型的集合、Type数据结构规格可通过 schema 查找、Member type数组的元素类型、引用的目标类型等不进入全局注册表。其核心入口是 src/legacy/Schema.ts 中提供的Schema.compile()它把用户写的 schema 定义编译成一个带registry类型注册表和localTypeNames本地类型名的运行时对象get(name)按名取类型getTypeNames()返回全部类型名getLocalTypeNames()只返回当前 schema 本地注册的类型。结合 CHANGELOG 的时间线2025 年 4 月的 3.86 到 2026 年 9 月的 6.13对应package.json当前版本 6.14.1可以归纳出三条并行演进的主线演进主线代表版本核心目标Schema Descriptor描述符3.93、3.98、4.7、4.20、5.21把 schema 序列化、同步到服务器、最小化 UI 阻塞类型提取与内联提升5.0、4.15、4.2、5.21为 typegen / GROQ 生成干净、无冗余的类型图验证与告警6.13、6.12、5.9、5.14、5.10能力化验证结果、无头验证、坏 schema 只警告不崩溃下面的章节将沿这三条主线逐一展开并补充依赖生态get-it、groq-js、sanity/icons的更新节奏。二、Schema Descriptor把类型编译结果变成可同步的注册表2.1 背景为什么要引入描述符3.93.0 引入 serialize schema in debug mode#9503 中有直接说明完整 schema 被表示为sanity.schema.registry注册表它是由sanity.schema.namedType具名类型和可能的其他注册表组成的集合。例如一个普通的 Studio其注册表包含blogPost具名类型继承document字段title、body再加上一套独立的内建类型注册表document、object等。把内建类型单独放一个注册表是为了让服务器可以在多个不同 schema 之间复用这套内建类型从而让同步更高效。2.2 描述符语言的两个核心概念extends而非type在描述符世界中名称不属于类型定义本身。你在 Studio 里写fields: [{name: title, type: string}]实际上声明的是一个继承自string的全新子类型只是恰好没有覆盖任何属性。因此描述符语言用extends: string来显式表达子类型化关系见 src/descriptors/README.md。引用reference使用具名类型to: [author]这种写法与 Studio 的to: [{type: author}]等价但描述符明确只关心引用的名称name因为其内部创建的子类型属性从不被使用。2.3 实现核心DescriptorConvertersrc/descriptors/convert.ts 中的DescriptorConverter是序列化的核心它做了三件与 CHANGELOG 直接对应的事字段去重de-dupe对应 4.20.0 de-dupe re-used fields in the descriptorconvertCommonTypeDef中用options.fields这个Mapobject, ObjectField记录字段对象 → 描述符值第二次遇到同一字段时写入duplicateFields并在后续用{__type: hoisted, key}的 rewrite map 指向首次出现的较小路径isLessCanonicalName保证保留最简规范路径。数组元素of的去重走同样的arrayElements/duplicateArrayElements机制。字段对象缓存对应 4.20.0 cache generated field objects转换结果按 schema 缓存于WeakMapSchema, SetSynchronizationRegistryType二次调用直接命中。最小化 UI 阻塞对应 4.20.0 minimize blocking the UI转换分遍历成描述符与序列化含 SHA256 哈希两步且通过SchedulerIdleScheduler或同步调度器逐个类型处理避免一次性阻塞主线程代码注释明确说明该设计目前未使用后台 Worker因为类型对象本身不可序列化。2.4 验证、i18n 与排序4.7.0 的三连发4.7.0 一次性补上了三块描述符能力handle validations#10457maybeValidations不仅序列化显式声明的验证规则还会重建隐含规则——例如options.list自动推导enum规则、url推导uri、slug推导custom、reference推导reference、email推导email。代码注释解释这是因为描述符操作在 ownProps 上继承自类型的默认验证会丢失必须补回。convertRuleSpec则把RuleSpec如min/max/length/regex/uri/custom/presence等 flag逐一映射为可序列化的RuleType。serialize i18n properties#10540maybeI18n将I18nTextRecord转换为{ns, key}的 LocalizedMessage 格式应用于字段组groups、排序orderings等带i18n属性的场景。serialize orderings properties#10550maybeOrdering序列化排序定义name、title、by其中maybeOrderingBy会保留directionasc/desc和nullsfirst/last字段——后者与 5.17.0 的 ability to control undefined/null sorting#12367直接衔接。2.5 不可序列化值的 Marker 机制描述符使用 JSON 无法原生表达的值时会用带__type属性的对象标记见 src/descriptors/README.md__type: function— 函数__type: cyclic— 循环引用__type: number— 数字序列化为字符串因为 JSON 对数字定义不充分__type: undefined— 数组内的 undefined__type: unknown— 其他未知值convertUnknownsrc/descriptors/convert.ts实现了这套标记逻辑还额外支持 React 元素__type: jsx与最大深度标记__type: maxDepth默认MAX_DEPTH_UKNOWN 5。2.6 与 Manifest 提取的双向通道除描述符外schema 还通过两套 manifest API 支持双向重建提取extractManifestSchemaTypessrc/manifest/extractManifestSchemaTypes.ts尽力提取用户定义 schema 的可序列化属性title、description、readOnly/hidden、fieldsets、fields、to/of、validation、block 的 marks/lists/styles/of 等retainSerializableProps递归裁剪函数、空字符串等不可序列化内容深度上限MAX_CUSTOM_PROPERTY_DEPTH 5ensureCustomTitle还会在 title 等于默认 startCase 结果时省略该字段以减小 payload。重建createSchemaFromManifestTypessrc/manifest/createSchemaFromManifestTypes.ts反向把 JSON manifest 还原为可编译的 schema——先validateSchemagroupProblems校验再把 JSON 化的验证规则coerceValidation成真正的Rule最后以parent: builtinSchema编译。三、可移植文本Portable Text装饰器、国际化与默认导出3.1 保留 block decorators6.2.06.2.0 有两个相互关联的修复preserve portable text block decorators in schema descriptor#13288与preserve an explicit empty block decorator set#13291。实现位于maybeBlockMarkssrc/descriptors/convert.ts通用的转换器之所以能拾取 styles / lists / annotations / inline objects是因为它们在编译后的 block 上以字段形式存在如style字段的options.list唯独装饰器以span.decorators元数据形式存在没有字段表示不特殊处理就会被整体丢弃。修复后装饰器与 style/list options 走同一个convertUnknown遍历因此i18nTitleKey、函数形式的icon标记为function/jsx等结构都能一致地序列化。关键语义显式空集合marks.decorators: []用于禁用全部装饰器必须保留为[]它与未声明装饰器编译为默认集合是两种不同状态——若折叠为undefined消费方会回退到默认装饰器集合等于静默重新启用了 schema 明确禁用的装饰器。3.2 允许 i18nTitleKey 与自定义注解6.11.0允许在 portable-text 的 styles / lists 上使用i18nTitleKey并导出默认值#13494。这与 5.6.0 的 exportDEFAULT_ANNOTATIONSandDEFAULT_DECORATORS#11916一脉相承。5.6.0另一项允许自定义 object types 作为 portable text 注解annotations。3.3 默认装饰器、注解、样式与列表的源码依据默认值定义在 src/legacy/types/blocks/defaults.ts并从 src/_exports/index.ts 公开导出DEFAULT_DECORATORSstrong、em、code、underline、strikeThrough五项每项均带title、value与i18nTitleKey如inputs.portable-text.decorator.strong。DEFAULT_ANNOTATIONS默认只有link注解其href字段用Rule.uri({scheme: [http,https,tel,mailto], allowRelative: true})校验并以options.modal {type: popover}指定弹层形式。DEFAULT_BLOCK_STYLESnormal、h1–h6、blockquote共 8 种。DEFAULT_LIST_TYPESbullet与number编号列表。以 6.x 引入i18nTitleKey为背景默认值对象中每个条目都携带i18nTitleKey字段这正是 Studio 国际化i18n标题渲染的输入。四、验证系统从结果对象到能力感知4.1 capability-aware results6.13.0与 headless 验证6.12.06.12.0add headless document validation package#14093把文档验证抽成可在无头环境Node/CI直接运行的独立包摆脱对 React 渲染环境的依赖。6.13.0add capability-aware results#14306验证结果按能力capability区分——即验证器能获得哪些上下文能力从而让结果对调用方更精确可判。同期 6.13.0 还有性能优化 consolidate equality checks on dequal/lite and domain comparators#14501把相等性判断统一收敛到dequal/lite与领域比较器上这也是package.json中依赖dequal的用途。4.2 早先的验证告警改进5.9、5.10、5.145.9.0验证上下文加入hidden#12050当数组包含多个解析为相同 JSON 类型的原始类型时输出告警#12095——避免出现无法区分两个 string 成员的隐性歧义。5.10.0文档类型被用作字段类型时给出告警#12151数组成员中同样告警#12165同时不为顶层文档类型的引用创建 inline refs#12168保证对文档的引用保持顶层、可全局解析。5.14.0add warnings when element is not valid instead of crashing studio#12262schema 中存在非法元素时改为输出警告而非让整个 Studio 崩溃显著提升了配置错误的可恢复性。五、GROQ 类型提取与内联提升inline hoisting5.1 5.0.0 破坏性变更schema inline hoisting5.0.0 引入了 BREAKING CHANGE schema inline hoisting#11521 的extractSchema()中分三趟完成依赖分析与提升检测sortByDependencies对类型做拓扑排序依赖在前并利用对象同一性检测重复的内联字段——Sanity 编译后的 schema 在同一个内联类型被多处引用时会复用同一个ObjectField对象因此可以用对象引用而非结构比较来识别repeated字段。pickRepeatedName会为重复字段从最短路径后缀开始挑选唯一名称如content→blocks.content→post.blocks.content冲突时追加数字后缀。提升类型创建为所有 repeated 内联字段先创建顶层具名类型定义保证在引用之前存在reserveRefName为引用目标生成唯一的.reference名称并处理命名冲突。主类型转换按依赖序处理每个类型遇到被提升的字段时输出{type: inline, name: hoistedName}引用而非复制结构。对文档类型的引用则因为 groq-js / codegen 尚不支持内联文档引用回退为内嵌输出。5.2 相关修复与边界5.0.1sort out conflict between hoisted ref types and other types#11579解决提升引用与既有类型名冲突。4.21.0修复inline type reference another inline type的回归#11411。4.15.0extract inline non-objects#10990对象之外的内联原始类型也能被正确提取。4.2.0preserve object for inline types#10030。5.3 为类型生成服务的必填字段语义4.5.0mark image data as required, for typegen#10285为了让类型生成器得到准确的类型image 的data被标记为必填。5.13.0update fileAsset and imageAsset required fields#12261调整 asset 类型的必填字段集合与 Content Lake 中 asset 文档的真实结构对齐。5.21.0support extracting object type without fields#12605与 convert missing descriptor properties and expand test coverage#12607补齐了无字段对象类型的提取与描述符属性覆盖。extractSchema中还体现了enforceRequiredFields选项src/sanity/extractSchema.ts开启时字段optional仅当字段非必填才为true否则一律标记 optional。必填判断通过 Proxy 探测验证函数是否调用.required()assetRequired()则驱动 asset 属性必填。六、资源、媒体库与其他能力点3.99.0Media Library 视频集成#99095.3.0为 media-library 增加 thumbhash 支持。4.20.0支持私有资源private assets#11316。6.5.0add descriptor upload client#13284描述符体系配套的上传客户端用于把序列化后的 schema/资源上传到服务端。4.20.1handle asset as array member with enforce required fields#11370当 asset 作为数组成员时也正确处理必填字段强制。4.3.0allow all fields group customizations#10094字段组fields groups自定义全面放开。七、破坏性变更与升级注意面向 6.xCHANGELOG 明确标注了两处 BREAKING CHANGES6.0.0放弃 Node 20 支持#12859 的engines: {node: 22.12}及browserslistnode 22.12、baseline 2024一致——升级到 6.x 前请确认运行时 Node 版本 ≥ 22.12。5.0.0schema inline hoisting。提取出的 GROQ schema 会以inline类型引用提升后的具名类型消费方typegen、groq-js 查询推理需要支持InlineTypeNode语义。依赖生态的同步节奏CHANGELOG 中大量条目为依赖更新它们同样影响行为边界groq-js6.x 升至 v2#13677此前在 3.x/4.x/5.x 间持续小版本跟进1.17 → 1.30 等extractSchema产出的类型图直接消费 groq-js 的类型节点TypeNode、InlineTypeNode、UnionTypeNode等见 src/sanity/extractSchema.ts。get-it从 8.8.x 逐步推进到 9.x#14079影响 schema 同步与上传客户端使用的 HTTP 层。sanity/icons3.x → 5.x#13409并伴随 4.0.0 的 debarrel 导入优化#13393减小打包体积。sanity/types作为 workspace 依赖在 3.86.x 随版本同步见 CHANGELOG 底部条目是类型层面的硬性配套。工程化3.94.2 起停止向 npm 发布 src 文件夹#97444.13.0 统一 vitest/jsdom 覆盖版本package.json的发布产物仅包含lib目录files: [lib]导出映射区分 monorepo 源码入口与发布入口。八、如何在当前仓库验证这些能力查看默认值导出src/_exports/index.ts 公开了Schema、Rule与DEFAULT_ANNOTATIONS、DEFAULT_BLOCK_STYLES、DEFAULT_DECORATORS、DEFAULT_LIST_TYPES默认值本体在 src/legacy/types/blocks/defaults.ts。阅读描述符实现src/descriptors/convert.ts 的DescriptorConverter与配套说明 src/descriptors/README.md。运行测试仓库在 test/ 下提供 vitest 用例覆盖 schema 提取extractSchema/含快照、legacy 编译legacy/与验证validation/使用pnpm --filter sanity/schema test可执行。查看真实使用场景本仓库的各类 Studio 是 schema 定义的最佳实例例如 dev/design-studio/schemaTypes含 block 类型pt.ts、数组嵌套arrayInArray.ts、dev/page-building-studio/schemaTypeshero、logoCarousel 等页面区块以及 dev/test-studio/schema 中覆盖全类型与边界场景的调试 schema。九、小结从 3.86 到 6.13sanity/schema完成了从纯本地类型编译到可序列化、可同步、可反向重建的体系化升级描述符注册表让 schema 能被高效同步到 Content Lake 并在服务端复用内建类型去重、缓存与调度器让序列化在保持正确性的同时最小化 UI 阻塞可移植文本的装饰器与i18nTitleKey保留保证了富文本配置不丢失语义内联提升让 GROQ 类型图干净无冗余能力感知的验证结果则把校验精度提升到一个新层次。对于升级者核心提醒是6.x 要求 Node ≥ 22.125.0 起的 inline hoisting 改变了类型提取输出——理解这两点即可安全地享受后续所有能力收益。【免费下载链接】sanitySanity Studio – Rapidly configure content workspaces powered by structured content项目地址: https://gitcode.com/GitHub_Trending/sa/sanity创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价