
ruru-components 2.0 演进全解析Crystal Monorepo 中 Grafast 风格 GraphiQL 组件库的架构、迁移与实战指南【免费下载链接】crystal Graphiles Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!项目地址: https://gitcode.com/gh_mirrors/cry/crystalruru-components 是 Graphile Crystal Monorepo 中 RuruGrafast-flavoured GraphiQL 发行版的底层 React 组件库。本文以 grafast/ruru-components/CHANGELOG.md 为主线完整梳理其从 2.0.0-alpha 到 2.0.0 的架构级演进——包括基于 GraphiQL v5 与 Monaco 编辑器的彻底重建、ruru/bundle到ruru/static的静态资源模型变迁、ruruHTMLParts到ruruHTML的中间件重命名、clientConfig的引入以及 Explain、onError、SDL 导出等核心能力。读完本文你将掌握 Ruru 2.x 的组件架构、配置模型与从旧版本迁移的完整清单并能直接结合仓库源码深入验证每个细节。一、ruru-components 在 Crystal Monorepo 中的定位在 package.json 中ruru-components 的自我描述是Grafast-flavoured GraphiQL distribution; the underlying React components即它是 Ruru 的React 组件层向上被ruru服务器集成层提供ruru/server、ruru/static等入口与grafservGraphile 的服务器中间件框架消费向下依赖ruru-types纯类型包与grafastGraphile 的查询规划执行引擎。从 package.json 可以看到它的核心依赖栈依赖版本范围作用graphiql^5.2.1底层 IDE 框架v5 起内置 Monaco 编辑器graphiql/react/graphiql/toolkit^0.37.2/^0.11.3GraphiQL 的 React 组件与 fetcher 工具集graphiql/plugin-explorer等插件^5.1.1文档/历史/资源管理器插件mermaid^11.12.1计划图plan diagram渲染prettier^3.6.2查询格式化react/react-dom^19.2.0界面渲染graphql-ws^6.0.5WebSocket 订阅协议grafast、ruru-typesworkspaceMonorepo 内部依赖组件库对外只暴露两个导出dist/index.js组件本体与./ruru.css样式。运行环境要求 Node ≥ 22engines字段并要求 peer 依赖graphql^16.9.0。二、核心组件架构从源码看 Ruru 是如何拼装起来的组件库的源码入口是 src/index.tsx 与 src/ruru.tsx。在ruru.tsx中Ruru组件将 GraphiQL 的各个插件、存储、fetcher 组装成一个完整 IDEconst explorerPlugin makeExplorerPlugin({ showAttribution: false }); const plugins [ DOC_EXPLORER_PLUGIN, DOWNLOAD_PLUGIN, HISTORY_PLUGIN, explorerPlugin, EXPLAIN_PLUGIN, ];五个插件分别对应文档浏览器、SDL 下载、历史记录、资源管理器、Explain。DOWNLOAD_PLUGIN与EXPLAIN_PLUGIN是 Ruru 独有的扩展定义在 src/plugins/download.tsx 与 src/plugins/explain.tsx 中。组件树的结构ruru.tsx为GraphiQLProvider └─ ExplainContext.Provider └─ HistoryStore / DocExplorerStore └─ RuruInnerGraphiQLInterface ├─ GraphiQL.LogoRuru 品牌 ├─ GraphiQL.ToolbarPrettify / Merge / Copy / Options 菜单 └─ GraphiQL.FooterRuruFooter工具栏的 Options 菜单ruru.tsx 第 189-259 行提供了四组开关全部持久化到localStorageExplain、Verbose、Condensed以及onError 行为选择PROPAGATE / NULL / HALT。存储实现见 src/hooks/useStorage.ts其中定义了所有存储键存储键localStorage key取值explainRuru:explaintrue/verboseRuru:verbosetrue/condensedRuru:condensedtrue/缺省视为开启onErrorRuru:onErrorPROPAGATE/NULL/HALT/explainSize等Ruru:explainSize等面板尺寸与开关状态三、2.0.0-beta.33基于 GraphiQL v5 与 Monaco 的重建CHANGELOG 中最重要的一条变更来自 2.0.0-beta.33PR #2578标记为 Ruru has been rebuilt! The loading methods and APIs have changed!。这次重建是理解整个 2.0 系列架构的钥匙编辑器从 CodeMirror 切换到 MonacoRuru 现在构建在 GraphiQL v5 之上使用与 VSCode 相同的 Monaco 编辑器带来更熟悉的快捷键例如在编辑器中按 F1 打开命令面板与更多功能例如可以在 variables JSON 里写注释。放弃单 HTML 文件方案由于 Monaco 依赖 worker 线程、需要额外文件Ruru 不能再以单个 HTML 文件分发转而采用bundle splitting——prettier与mermaid都被打包进来但按需加载loadMermaid()/loadGrafastMermaid()的动态import见 src/components/Explain.tsx并且离线可用。新增ruru/static静态资源入口ruru/bundle不再存在必须通过ruru/static为各种 JS 服务器提供静态文件服务。3.1ruru/static静态资源服务的源码实现重建后静态资源服务逻辑位于 grafast/ruru/src/static.ts。该模块提供两个核心 APIgetStaticFile({ staticPath, urlPath, acceptEncoding, disallowDevAssets })根据请求路径返回静态文件及其响应头。所有文件以Brotli 压缩后的 Buffer形式缓存bundleCode.ts约 4MBsource map 在bundleMeta.ts约 10MB可通过disallowDevAssets跳过若客户端Accept-Encoding不含br则实时解压。serveStatic(staticPath)返回一个兼容 Node / Connect / Express 的中间件负责剥离staticPath前缀、匹配文件、处理ETag304 缓存。值得注意的细节是 MIME 类型映射static.ts 第 25-32 行js/css/ttf/map 等类型在此声明未知扩展名会直接抛错——这保证了分发资源的完整性。四、HTML 定制 API 演进defaultHTMLParts→config.htmlParts/makeHTMLParts2.0.0-beta.33 同时废弃了defaultHTMLParts改为config.htmlPartsGraphile Config 用户写作preset.ruru.htmlParts。关键变化是条目从字符串变成了回调函数大幅减少样板代码-import { defaultHTMLParts } from ruru/server; const config { htmlParts: { - metaTags: defaultHTMLParts.metaTags !-- local override --, metaTags: (base) base !-- local override --, } }也可以直接使用makeHTMLParts(config)。在 grafast/ruru/src/server.ts 中可以看到makeHTMLParts的实际行为它把staticPath默认https://unpkg.com/ruruversion/static/见第 15 行、endpoint、subscriptionEndpoint以及用户通过clientConfig传入的配置烘焙进客户端配置对象。同时该文件提供了escapeJS/escapeHTML两个转义工具用于安全地把配置注入 HTML——这是对 CHANGELOG 中更安全类变更如 null prototype 对象的直接呼应。五、Grafserv 集成ruruHTMLParts→ruruHTML对于 Grafserv 用户2.0.0-beta.33 将plugin.grafserv.middleware.ruruHTMLParts更名为ruruHTML——去掉Parts并保证next()是函数的最后一行const plugin { grafserv: { middleware: { - ruruHTMLParts(next, event) { ruruHTML(next, event) { const { htmlParts, request } event; htmlParts.titleTag title${escapeHTML( Ruru | request.getHeader(host), )}/title; return next(); }, }, }, };源码层面grafast/grafserv/src/hooks.ts 第 50-58 行 保留了ruruHTMLParts作为向后兼容的旧钩子名它会被自动转注册为ruruHTML中间件参数结构不变{ resolvedPreset }、htmlParts、request。新的ruruHTML钩子接收的是RuruHTMLEvent含htmlParts与config定义在 grafast/grafserv/src/index.ts其中旧钩子被标记为deprecated。中间件的实际执行链在 grafast/grafserv/src/middleware/graphiql.ts先makeHTMLParts(config)生成默认 HTML 片段若存在ruruHTML中间件则传入事件并调用否则直接调用ruruHTML(config, htmlParts)输出最终 HTML。六、clientConfig客户端配置的显式边界2.0.0-beta.33 的另一项重要设计是引入RuruConfig.clientConfig专门存放会被发送到浏览器端的 props。同时RuruServerConfig将原先顶层平铺的客户端选项editorTheme、debugTools、eventSourceInit标记为deprecated要求移入clientConfigconst config { endpoint: /graphql, clientConfig: { editorTheme: dark, }, }对应的类型定义在 grafast/ruru-types/src/index.tsRuruProps显式挑选了 GraphiQL 的editorTheme、defaultTheme、forcedTheme、maxHistoryLength、inputValueDeprecation、schemaDescription、showPersistHeadersSettings、initialQuery、initialVariables等 props并新增了 Ruru 自己的endpoint、subscriptionEndpoint、debugTools、eventSourceInit、fetcher。其中debugTools?: Arrayexplain | plan控制用户可见的调试工具explain - output the SQL executed、plan - output the plan executedeventSourceInit会被原样传给new EventSource(url, eventSourceInit)除规范内的withCredentials外还支持实现相关的扩展选项例如reconnectInterval: 1000、maxReconnectAttempts: 3——这正对应 CHANGELOG 2.0.0-beta.25PR #2266中允许覆盖 EventSource 配置选项的修复。clientConfig的烘焙逻辑同样在makeHTMLParts中完成...config.clientConfig覆盖旧式顶层选项最后再强制写入staticPath/endpoint/subscriptionEndpoint保证服务器自管理的配置不会被客户端覆盖。七、ExplainSQL 与执行计划的可视化调试Explain 是 Ruru 相对通用 GraphiQL 的核心差异化能力其演进贯穿整个 CHANGELOG2.0.0-0.6默认开启 explain修复 fetcher 修改不可变对象的问题。2.0.0-beta.31升级到 Mermaid 11并降低计划图中多态polymorphism的冗余度修复增量交付结果中 explain 输出未隐藏的问题。2.0.0-alpha.2支持将 mermaid 计划图下载为 SVG。7.1 请求侧explain 请求头的注入src/hooks/useFetcher.ts 展示了 explain 是如何从 UI 开关传导到 HTTP 请求的当工具栏开启 Explain 且debugTools包含explain时fetcher 会为每个请求附加两个头X-PostGraphile-Explain: on X-GraphQL-Explain: plan,sql这两个头同时通过wsConnectionParams传给 WebSocket 订阅连接对应 CHANGELOG 2.0.0-beta.13 中headers 未随 websocket connectionParams 发送的修复。7.2 响应侧explain 结果的提取与隐藏fetcher 对每个响应做processPayload处理useFetcher.ts 第 173-240 行读取extensions.explain若格式合法isExplainResultsLike校验operations[].type/title延迟 100ms 写入explainResults状态供 Explain 面板消费若未开启 Verbose则通过hideProperty将 explain 字段设为不可枚举从返回结果中隐藏只删除或改为非枚举取决于deleteExplain参数兼容 PostGraphile v4 时代的顶层explain数组映射为Legacy explain N的 SQL 操作对 introspection 查询IntrospectionQuery短路避免干扰用户。7.3 展示侧SQL 与计划图的渲染Explain 面板由 src/components/Explain.tsx 实现支持两类操作结果SQL 操作type: sql展示EXPLAIN计划文本与执行过的 SQL 查询均带复制按钮SQL 通过FormatSQL组件格式化对应 CHANGELOG 2.0.0-1.1 / 2.0.0-beta.2 中SQL 别名格式化与别名检测修复计划操作type: plan通过grafast/mermaid的planToMermaid渲染计划图支持复制 plan JSON、一键保存 SVGSave Mermaid Diagram按钮内部调用mermaid.render生成 SVG 文件对应 2.0.0-alpha.2 的能力点击可展开全屏查看。八、onError RFCPROPAGATE / NULL / HALT 三种错误行为2.0.0-beta.36PR #2694为 Ruru 增加了对 GraphQLonErrorRFC 的支持实现了PROPAGATE、NULL、HALT三种行为。这在 UI 上直接体现为工具栏 Options 菜单中的三个单选选项ruru.tsx 第 226-258 行onError: PROPAGATE传统 GraphQL 错误处理方式Traditional GraphQL error handlingonError: NULL客户端负责错误处理Client becomes responsible for error handlingonError: HALT遇到第一个错误即停止执行Stop execution on the first error。选择结果存入Ruru:onError而 fetcher 在发起请求前会读取该值并合并进请求参数useFetcher.ts 第 245-249 行const onError storage.get(onError); const args [ onError ? { ...params, onError } : params, ...rest, ] as const;九、实时能力演进WebSocket 订阅与事件流订阅能力是 Ruru 一路迭代的重点2.0.0-0.7PR #200为 Ruru 加入 WebSocket 订阅支持2.0.0-beta.32PR #2583 升级到graphql-ws v62.0.0-beta.25PR #2266修复 EventSource 断线导致的白屏死机改为优雅错误处理并允许覆盖 EventSource 配置2.0.0-0.8升级 GraphiQL获得 watch mode 修复。在 fetcher 实现中订阅 URL 由subscriptionEndpoint或回退到endpoint经makeWsUrl转换为ws:///wss://useFetcher.ts 第 78-88 行并与普通 HTTP 请求共用同一套 headers 作为wsConnectionParams。流式结果的处理同样细致fetcher 会拦截每个fetch响应读取X-GraphQL-Event-Stream响应头来发现流式端点streamEndpoint对应 Grafserv 的增量交付/Live Query 支持并交由useGraphQLChangeStreamsrc/hooks/useGraphQLChangeStream.ts驱动界面更新。对于 async iterable 结果processPayload会包装迭代器的next()逐个处理增量 payload 中的 explain 数据对应 2.0.0-beta.31 中增量交付结果隐藏 explain的修复。十、UI/UX 与依赖升级路线图10.1 Condensed 模式2.0.0-beta.34PR #2646引入Condensed紧凑模式并默认启用用户可在编辑器视图的 settings 齿轮中取消勾选来关闭。源码中condensed状态存储在Ruru:condensed默认非空即视为开启useStorage.ts 第 78-83 行 的toggle逻辑condensed键在值为 null 时也执行关闭RuruInner据此给GraphiQLInterface追加condensedCSS 类。2.0.0-beta.35 还修复了折叠模式下侧边栏边框的显示问题。10.2 主题控制2.0.0-beta.33PR #2605新增defaultTheme与forcedThemeprops 并透传给 GraphiQL2.0.0-beta.34PR #2645升级到最新的 GraphiQL。此外 CHANGELOG 2.0.0-0.8 中升级 GraphiQL 获得 watch mode 修复说明主题/编辑器的行为始终跟随 GraphiQL 上游演进。10.3 React 与 GraphiQL 版本升级2.0.0-beta.3Ruru 运行在 React 18 上模块转为ESM以兼容 GraphiQL2.0.0-beta.32 升级到 GraphiQL v4CSS 导入路径变更——graphiql/graphiql.css→graphiql/style.css、graphiql/plugin-explorer/dist/style.css→graphiql/plugin-explorer/style.css同时升级到React 19PR #2585并修复 ToolbarMenu 的 button-in-button 警告PR #25822.0.0-beta.33升级到 GraphiQL v5Monaco 基础。十一、稳定性、安全性与工程化改进CHANGELOG 中大量 patch 级变更指向工程健壮性很多都能在源码中找到对应实现版本变更源码佐证2.0.0-0.6修复 fetcher 修改不可变对象processPayload中通过对象展开{...inResult}、{...extensions}创建可变副本后再隐藏 explainuseFetcher.ts2.0.0-beta.25修复 EventSource 断线白屏、允许覆盖 EventSource 配置eventSourceInit透传ruru-types/src/index.ts2.0.0-beta.31修复增量交付中 explain 未隐藏async iterable 包装中调用processPayload(value, true)2.0.0-rc.4 (PR #2877)Safety - use null prototype objects in more placesfetcher headers 使用Object.create(null)useFetcher.ts 第 154 行、存储缓存同样使用 null 原型对象useStorage.ts 第 45 行2.0.0-rc.4 (PR #2881)修复 WebSocket 意外断开时输出{isTrusted: true}的问题async iterable 的next()错误分支检测e.target instanceof WebSocket改写为友好错误信息useFetcher.ts 第 278-285 行2.0.0-rc.6 (PR #2937)消除悬空 promise降低未处理 rejection 导致进程退出的概率ourFetch的result.then(..., () {})显式吞掉错误分支useFetcher.ts 第 133-151 行2.0.0-rc.4 (PR #2873)TypeScript 配置支持 Node 22 最低版本engines.node: 22package.json2.0.0-0.9修复 header 保存showPersistHeadersSettings默认开启ruru.tsx 第 101 行2.0.0-beta.13修复 explorer 插件中输入字符被覆盖依赖 GraphiQL 上游修复2.0.0-beta.13 (PR #1931)支持 deprecated arguments 展示inputValueDeprecation/schemaDescription默认 trueruru.tsx 第 90-91 行此外还有一系列依赖与工程治理层面的变更2.0.0-beta.36 移除 peer dependency 的 optionality 以满足 pnpm 安装算法PR #2678、将 mermaid 从 11.8.1 升级到 11.10.0PR #2676dependabot、2.0.0-beta.37 更新graphql版本范围PR #2730、2.0.0-1.1 要求 TypeScript v5PR #260、2.0.0-rc.5 启用rewriteRelativeImportExtensions与erasableSyntaxOnly源码中使用.ts扩展名导入见 ruru.tsx 的 import 语句、以及 2.0.0-rc.7 清理 package.json 并改用固定标识符的 peer dependencies 与 trusted publishingPR #2990。十二、包结构拆分ruru-types 的独立2.0.0-rc.5PR #2912将 Ruru 拆出ruru-types包——stripped down vs ruru-components。类型收归 grafast/ruru-types/src/index.ts 后ruru-components 的 src/interfaces.ts 只剩一行转导出export type { Fetcher, RuruProps } from ruru-types;这一拆分让ruru服务器层可以只依赖类型包而无需加载整个组件库同时配合 2.0.0-rc.5 中一致的类型导出语法PR #2910与 peerDependencies 修复PR #2915构成了 2.0.0-rc.7 依赖关系的最终形态ruru-types2.0.0-rc.6grafast1.0.0-rc.9。十三、2.0 系列完整版本时间线与升级检查清单从 CHANGELOG 可以梳理出完整的发布脉络2.0.0-0.5整体安全与兼容性修复→2.0.0-0.6默认开启 explain→2.0.0-0.7WebSocket 订阅→2.0.0-0.8/0.9GraphiQL 升级、header 保存修复→2.0.0-1.1TypeScript v5→2.0.0-alpha.xSVG 下载、TS/tslib 升级→2.0.0-beta.xReact 18、ESM、onEdit/初始 query 插件、schema 抓取重做、EventSource 修复、condensed、GraphiQL v4/v5、Monaco 重建、clientConfig、onError RFC→2.0.0-rc.xNode 22、null prototype、isTrusted修复、ruru-types 拆分、SDL 导出→2.0.0与 rc.7 完全一致。如果你的项目正在从 Ruru 旧版本迁移按 CHANGELOG 的 标记整理出的必改清单如下加载方式ruru/bundle已删除改为ruru/static提供静态文件配合 static.ts 的serveStatic或getStaticFile使用HTML 定制defaultHTMLParts→config.htmlParts回调函数形式或makeHTMLParts(config)Grafserv 中间件ruruHTMLParts→ruruHTML确保next()是最后一行旧钩子名仍可用但已标记 deprecated客户端配置editorTheme、debugTools、eventSourceInit从RuruServerConfig顶层移入clientConfigCSS 导入若手动引入样式GraphiQL v4 起使用graphiql/style.css与graphiql/plugin-explorer/style.css运行环境Node ≥ 22peer 依赖graphql^16.9.0订阅协议graphql-ws6headers 通过connectionParams自动携带。结语ruru-components 的 2.0 演进本质上是一次为 GraphiQL 注入 Grafast 能力的架构升级Monaco 编辑体验、按需加载的资源模型、以clientConfig为界的配置体系以及 Explain / SDL 导出 / onError 等深度集成都服务于让开发者在一个 IDE 里同时观察查询结果、SQL 与执行计划这一目标。无论是作为 Graphile 生态的使用者还是希望借鉴 GraphiQL 二次封装经验的开发者都可以从 src/ruru.tsx、src/hooks/useFetcher.ts、ruru-types 的 RuruProps 与 grafserv 的 ruruHTML 钩子 四条路径入手对照本文逐层验证与扩展。【免费下载链接】crystal Graphiles Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!项目地址: https://gitcode.com/gh_mirrors/cry/crystal创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考