Relay Resolvers 字段弃用指南:用 @deprecated 标记客户端状态模式中的废弃字段
2026/9/24 17:08:39 网站建设 项目流程

Relay Resolvers 字段弃用指南:用 @deprecated 标记客户端状态模式中的废弃字段

【免费下载链接】relayRelay is a JavaScript framework for building>项目地址: https://gitcode.com/gh_mirrors/relay29/relay

在 Relay 中,GraphQL 允许通过@deprecated指令标记字段并附加可读的弃用原因。Relay Resolvers 把这套约定原样带到了客户端数据上:在客户端状态模式(client state schema)中通过 docblock 标签把字段标记为 deprecated 后,它们会获得与服务端 GraphQL 模式中废弃字段完全一致的处理。本文将以 relay-resolvers/deprecated 文档 为骨架,结合 Relay 编译器 docblock 解析与 Schema 生成源码,讲解弃用标注的语法、编辑器表现、Markdown 原因书写约定及其底层实现。

为什么要在客户端模式中标记弃用字段

Relay Resolvers 允许你在客户端用 TypeScript/Flow 函数为本地字段提供解析逻辑,这些字段最终会被编译进客户端扩展的 GraphQL 模式中。随着客户端状态模式不断演进,某些 Resolver 字段会逐渐被新方案取代——例如拆分得更细的字段、语义更明确的命名,或者被服务端字段所替代。此时如果不加任何标记,其他开发者仍会像使用新字段一样使用旧字段,导致新代码持续依赖即将被移除的逻辑。

@deprecated正是为解决这个问题而存在。按照 GraphQL 约定,被标记的字段会出现在 IDE 的自动补全与悬停提示中,并附带弃用原因,从而在编码阶段就引导开发者迁移到替代字段。Relay 官方文档明确指出:

GraphQL allows you to mark fields as@deprecatedand provide an optional human-readable reason. Relay Resolvers bring this same convention to your client data. By marking fields in your client state schema as deprecated they will receive the same treatment as deprecated fields in your server GraphQL schema.

也就是说,客户端 Resolver 字段的弃用体验与服务端字段完全对齐,开发者在客户端状态模式中标注的@deprecated,最终会被编译器翻译为真正的 GraphQL@deprecated(reason: ...)指令(下文源码部分会给出证据)。

在编辑器中的呈现方式

弃用字段会以两种方式在 Relay 的 VSCode 扩展(editor-support 文档)中被突出显示:

  • 自动补全(autocomplete)与悬停(hover):弃用字段会在补全列表与悬停卡片中标记为 deprecated;
  • 编辑器中渲染:弃用字段会被渲染为置灰(greyed out)并加上删除线(struck through)。

这套交互与许多主流 IDE 对服务端 GraphQL 废弃字段的处理一致,让开发者无需阅读源码注释即可直观识别应避免使用的字段。

值得注意的是,Relay 的 VSCode 扩展本身是一个独立发布、独立使用的语言服务插件,其仓库源码位于 vscode-extension/src,编译侧的语言服务逻辑在 relay-lsp/src。

弃用原因请使用 Markdown 书写

文档中有这样一条重要约定(以:::info提示块呈现):

GraphQL deprecation reasons are expected to be written in markdown. Relay Resolvers will render these descriptions as markdown in the VSCode extension.

即:GraphQL 的弃用原因文本按约定应使用 Markdown 书写,Relay Resolvers 会在 VSCode 扩展中以 Markdown 形式渲染这些描述。因此写原因时可以放心使用**加粗**inline code链接等 Markdown 语法,扩展会将其渲染成富文本而不是纯文本。

语法:@deprecated docblock 标签

标记字段弃用的方式非常直接:在 Resolver 函数上方的 docblock 中添加@deprecated标签,标签后可以跟可选的文本说明弃用原因。

文档中的完整示例:

/** * @RelayResolver Author.fullName: String * * @deprecated Google "Falsehoods Programmers Believe About Names" */ export function fullName(author: AuthorModel): string { return `${author.firstName} ${author.lastName}`; }

要点拆解:

  1. @RelayResolver Author.fullName: String:声明这是一个 Relay Resolver,字段名为fullName,挂在Author类型上,返回类型为String
  2. @deprecated标签:将其下方的 Resolver 字段标记为弃用;
  3. 标签后文本Google "Falsehoods Programmers Believe About Names":作为可选的人类可读弃用原因,直接进入最终 GraphQL 指令的reason参数。

无原因的简写形式

@deprecated也可以不跟任何文本,只保留标签本身。仓库中的解析测试夹具relay-resolver-deprecated-no-description.js验证了这种形式:当没有提供原因文本时,生成的指令只包含@deprecated而不带reason参数(对应 relay-resolver-deprecated-no-description.expected)。

与 @rootFragment 等标签的组合

@deprecated可以与其他 Resolver 标签自由组合。例如 relay-resolver-deprecated.js 展示了@deprecated@rootFragment同时使用的场景:

/** * @RelayResolver User.favorite_page: Page * @rootFragment myRootFragment * @deprecated This one is not used any more */ graphql` fragment myRootFragment on User { id } `

其编译产物(见对应的.expected文件)可以清晰看到弃用标注最终落地为标准的 GraphQL 指令:

extend type User { favorite_page: Page @relay_resolver(import_name: "favorite_page", import_path: "/path/to/test/fixture/relay-resolver-deprecated.js", fragment_name: "myRootFragment") @resolver_source_hash(value: "5a025e60e324c90396402649e1fafb03") @deprecated(reason: "This one is not used any more") }

注意这里@deprecated(reason: "This one is not used any more")就是客户端弃用标注经过编译器转换后的最终形态,与任何服务端 GraphQL 模式中的弃用字段完全同构。

源码级实现:docblock 标签如何变成 @deprecated 指令

Relay 编译器使用 Rust 实现了 docblock 的解析与 Schema 生成,这一链路对理解弃用机制很有帮助。

指令名与参数名的定义

在 relay-docblock/src/ir.rs 中定义了弃用指令的名称常量:

static DEPRECATED_RESOLVER_DIRECTIVE_NAME: LazyLock<DirectiveName> = LazyLock::new(|| DirectiveName("deprecated".intern())); static DEPRECATED_REASON_ARGUMENT_NAME: LazyLock<ArgumentName> = LazyLock::new(|| ArgumentName("reason".intern()));

其中DEPRECATED_RESOLVER_DIRECTIVE_NAME对应 GraphQL 指令deprecatedDEPRECATED_REASON_ARGUMENT_NAME对应其reason参数。这从源码层面印证了文档所述"客户端弃用与服务端 GraphQL 弃用同等待遇"。

docblock 字段解析

docblock 解析层位于 relay-docblock/src/docblock_ir.rs。在构建字段 IR 时,AllowedFieldName::DeprecatedField被从待处理字段集合中取出并存入deprecated字段(见第 286、326、440 行附近的fields.remove(&AllowedFieldName::DeprecatedField)),说明@deprecated是 docblock 语法层的一等公民标签,会被专门识别而不是当作普通文本。

生成 GraphQL 指令

在 relay-docblock/src/ir.rs 的field_directives中,弃用字段被转换为常量指令:

if let Some(deprecated) = self.deprecated() { let span = deprecated.key_location().span(); directives.push(ConstantDirective { span, at: dummy_token(span), name: string_key_as_identifier(DEPRECATED_RESOLVER_DIRECTIVE_NAME.0), arguments: deprecated.value().map(|value| { List::generated(vec![string_argument( DEPRECATED_REASON_ARGUMENT_NAME.0, value, )]) }), }) }

这段代码的语义非常清晰:只要 docblock 中存在@deprecated标签,就会生成一个名为deprecated的 GraphQL 指令;若标签后附有原因文本,则将其包装为reason参数。这正是上一节测试夹具产物中@deprecated(reason: "...")的来源。

同样的逻辑也适用于弱对象(Weak Object)类型定义:在 ir.rs 的WeakObjectIr::type_definition中,self.deprecated存在时同样会向类型定义推入@deprecated指令,说明弃用标注不仅适用于字段,也适用于 Resolver 类型本身。

测试验证

弃用行为有专门的测试夹具覆盖,分布在两个测试入口下:

  • relay-docblock/tests/to_schema/fixtures:验证@deprecated标签如何被转换为最终 SDL 中的@deprecated(reason: ...)指令;
  • relay-docblock/tests/parse/fixtures:验证 docblock 解析阶段对@deprecated标签的语法识别,包括带原因(relay-resolver-deprecated.js)与不带原因(relay-resolver-deprecated-no-description.js)两种形式。

这些测试由 parse_test.rs 与 to_schema_test.rs 驱动,构成了"docblock 标签 → IR → GraphQL SDL 指令"这条完整链路的自动化回归保障。

使用建议

综合文档与源码,实践中有几点值得注意:

  1. 写清楚弃用原因:原因文本最终会成为 GraphQL 模式的一部分,直接暴露给 IDE 和下游工具,因此应尽量具体,最好指明替代字段或迁移方向;
  2. 原因文本使用 Markdown:Relay Resolvers 会在 VSCode 扩展中以 Markdown 渲染原因,合理使用格式能显著提升可读性;
  3. 弃用与删除是两回事@deprecated只是标记层面的提示,不会阻止字段被解析、查询或编译,它改变的是开发者在编辑器中的使用体验与模式可维护性;
  4. 尽早开始标注:客户端状态模式同样会随时间膨胀,从字段"过时"的第一天就标注弃用,比事后追溯更可靠。

总结

Relay Resolvers 的@deprecateddocblock 标签把 GraphQL 的弃用约定完整延伸到了客户端状态模式:开发者只需在 Resolver 函数上方加一行@deprecated及可选的 Markdown 原因,编译器便会将其转换为标准的@deprecated(reason: ...)GraphQL 指令,VSCode 扩展随后会在自动补全、悬停和编辑器中直观呈现弃用状态。从 relay-docblock 的源码与 测试夹具 可以看到,这条链路在编译器中是完整、有测试保障的一等公民能力——它让客户端数据模式与服务端模式在"字段生命周期管理"上保持了一致的体验。

【免费下载链接】relayRelay is a JavaScript framework for building>项目地址: https://gitcode.com/gh_mirrors/relay29/relay

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询