cm6-graphql 如何动态更新 CodeMirror 6 编辑器中的 GraphQL schema?

原创2026-09-14 12:42:55231 阅读
文章标签:开发工具后端

cm6-graphql 如何动态更新 CodeMirror 6 编辑器中的 GraphQL schema?

cm6-graphql 是 GraphiQL 仓库中的 CodeMirror 6 语言扩展,提供 GraphQL 解析、自动补全和 lint 能力。它在初始化时通过 graphql(schema) 扩展绑定一个 GraphQLSchema,但补全和诊断都依赖这个 schema,当后端 schema 发生变化时,不能重建整个 EditorView,需要把新 schema 动态写回编辑器。本文说明如何完成这次更新,以及如何确认编辑器确实用上了新 schema。

先准备好带 schema 的编辑器

动态更新的前提是编辑器已经按 cm6-graphql README 的方式初始化。先安装依赖:

npm install cm6-graphql

然后创建 EditorView,在 extensions 中放入 graphql(myGraphQLSchema):

import { basicSetup, EditorView } from 'codemirror';
import { graphql } from 'cm6-graphql';

const view = new EditorView({
  doc: `mutation mutationName {
    setString(value: "newString")
  }`,
  extensions: [basicSetup, graphql(myGraphQLSchema)],
  parent: document.body,
});

myGraphQLSchema 是 graphql 包导出的 GraphQLSchema 实例。README 同时提醒:CodeMirror 6 的样式需要自行提供 theme,basicSetup 不含主题,可参考仓库中的 cm6-graphql-parcel 示例入口 的做法(该示例使用了 oneDark 主题和 syntaxHighlighting)。

调用 updateSchema 写入新 schema

更新入口是 cm6-graphql 导出的 updateSchema,接收当前 EditorView 实例和新 schema:

import { updateSchema } from 'cm6-graphql';

const onNewSchema = schema => {
  updateSchema(view, schema);
};

onNewSchema 就是文档示意:在你拿到新 schema 的任何时机(例如 introspection 请求返回后)调用即可。不需要销毁或重建 EditorView。

它的实现见 state.ts:通过 view.dispatch 发送一个 StateEffect,把新值写入扩展内部维护的 schemaStateField。因为扩展内的补全和 lint 都是从该 state field 读取 schema 的,dispatch 完成后后续补全与诊断就会基于新 schema 计算。

参数类型是 GraphQLSchema | undefined,所以也可以传入 undefined 把 schema 清空。清空后 lint 不再产生诊断(lint.ts 中 !schema 时直接返回空数组),相当于把 schema 相关能力临时停用。

如果需要确认编辑器当前持有的 schema,可用同文件导出的 getSchema 读取:

import { getSchema } from 'cm6-graphql';

const current = getSchema(view.state);

注意 updateSchema 只更新 schema 本身。若还要改扩展选项(如 showErrorOnInvalidSchema),需要单独调用 updateOpts(view, opts),与 schema 更新是两条独立路径,不要混用。

验证新 schema 已生效

updateSchema 本身没有返回值,判断生效主要看编辑器的诊断行为。lint.ts 中 linter 配置了 needsRefresh,当 schemaStateField 或 options 前后不一致时会强制刷新诊断,也就是说 updateSchema 之后编辑器会用新 schema 重新校验文档内容。可以这样核对:

  1. 调用 getSchema(view.state),确认返回的引用是新 schema 实例(或按预期为 undefined);
  2. 在编辑器中查看 lint 报错:如果文档中引用了旧 schema 才有的字段,切换 schema 后对应诊断会刷新为与新 schema 一致的结果。

另外,schema 本身无效时 lint 会在文档开头报告 schema 校验错误(validateSchema 的结果),默认由 showErrorOnInvalidSchema: true 开启;若你不想让无效 schema 报全屏错误,初始化时用选项 { showErrorOnInvalidSchema: false } 关闭,选项结构定义见 interfaces.ts。

完整可运行的参考示例

仓库中的 cm6-graphql-parcel 示例 演示了从零到可运行的完整接线,按 README 的步骤操作:

pnpm install
pnpm start

pnpm start 启动 parcel 开发模式,pnpm build 产出生产文件。示例源码 中,EditorState 的 extensions 里传入 graphql(TestSchema, {...}),TestSchema 来自同目录的 testSchema.ts。它给出了一个可以直接对照的形态:schema 在初始化时随扩展注入,之后任何时刻用 updateSchema(view, 新Schema) 替换即可,编辑器实例保持不变。

小结

  • 初始化:extensions 中加入 graphql(schema),schema 为 GraphQLSchema 实例;
  • 动态更新:在拿到新 schema 时调用 updateSchema(view, schema),内部通过 StateEffect 更新 state,无需重建编辑器;
  • 验证:用 getSchema(view.state) 核对当前 schema,观察 lint 诊断随 schema 变化而刷新;
  • 边界:undefined 会清空 schema 并停用 lint;schema 无效时的报错由 showErrorOnInvalidSchema 控制;改扩展选项要用 updateOpts,与 updateSchema 分开。
登录后查看全文
graphiql